泛型,很多人因它放弃学习 TypeScript?

更新日期: 2019-11-05阅读: 2.3k标签: 泛型

1、ts的泛型很难吗?

如果你:

  1. 刚开始学ts
  2. 刚开始接触泛型
  3. 正在挣扎得学习ts的泛型

看到以下代码有没有很疑惑?

function makePair<
  F extends number | string,
  S extends boolean | F
>()

Java是和typescript一样支持泛型的,当我在大学开始学习Java的时候,我还是一个菜鸟码农,遇到难点(比如泛型)就直接跳过,能学多少学多少,回寝室就LOL开黑。直到大学毕业我依旧没有理解泛型的概念

可能你和我一样觉得泛型很难,下面我会分享我的理解,希望对你有所帮助。


2、一起来看一下makeState()这个函数

首先,我写了makeState这个函数,我们会用这个函数来讨论泛型

function makeState() {
  let state: number
  function getState() {
    return state
  }
  function setState(x: number) {
    state = x
  }
  return { getState, setState }
}

当你运行这个函数,我们会得到getState() 和 setState()这两个函数。

让我们来试一下,下面这段代码会打印出什么

const { getState, setState } = makeState()
setState(1)
console.log(getState())
setState(2)
console.log(getState())
1
2

会打印出1和2,没那么难对吧?

Note: 如果你正在使用react,你可能会发觉,makeState()和钩子函数useState()很像。这里也涉及到了闭包和ES6的解构赋值


3、我们传入字符串会如何?

我们把刚才给setState的入参1和2替换成字符串'foo'会输出什么呢?

const { getState, setState } = makeState()
setState('foo')
console.log(getState())
Argument of type '"foo"' is not assignable to parameter of type 'number'.

会编译失败,因为setState()需要的参数类型是number

我们可以用以下方法解决这个问题

function makeState() {
  // Change to string
  let state: string
  function getState() {
    return state
  }
  // Accepts a string
  function setState(x: string) {
    state = x
  }
  return { getState, setState }
}
const { getState, setState } = makeState()
setState('foo')
console.log(getState())
foo


4、挑战:获取两个不同类型的state

我们能不能修改makeState()这个函数,来输出两个不同类型的state,比如一个是字符串,一个是数字。
以下代码简略得表示我想表达的意思:

// One that only allows numbers, and…
const numState = makeState()
numState.setState(1)
console.log(numState.getState()) // 1
// The other that only allows strings.
const strState = makeState()
strState.setState('foo')
console.log(strState.getState()) // foo

要达到以上效果,我们可能需要创建两个内部不一样的makeState(),一个state的类型是数字,一个是字符串。
怎么用才能只写一个来实现呢?


5、实验一:设置多个类型

这是我们的第一个尝试:

function makeState() {
  let state: number | string
  function getState() {
    return state
  }
  function setState(x: number | string) {
    state = x
  }
  return { getState, setState }
}
const numAndStrState = makeState()
//数字
numAndStrState.setState(1)
console.log(numAndStrState.getState())
//字符串
numAndStrState.setState('foo')
console.log(numAndStrState.getState())
1
foo

结果看上去我们貌似成功了,但是这并不是我真实想要的,我们真正要实现的是只能输出数字state和只能输出字符串state。
numAndStrState是既能输出数字类型,又能输出字符串类型


6、实现二:使用泛型

接下来我们的泛型要登场了:

function makeState<S>() {
  let state: S
  function getState() {
    return state
  }
  function setState(x: S) {
    state = x
  }
  return { getState, setState }
}

makeState() 被定义成 makeState<S>(),你可以把<S>当作函数参数,但它传入的不是值,而是类型。
比如你可以传入数字类型:

makeState<number>()

在makeSate()这个函数内部state会变成数字类型

let state: S // <- number
function setState(x: S /* <- number */) {
  state = x
}

这样就实现了只能输出数字state

// Creates a number-only state
const numState = makeState<number>()
numState.setState(1)
console.log(numState.getState())
// numState.setState('foo') 输入字符串foo会报错

同理我们也可以实现只能输出字符串state

// Creates a string-only state
const strState = makeState<string>()
strState.setState('foo')
console.log(strState.getState())
// strState.setState(1) 输入数字1会报错

Note: 我们把makeState<S>()称作泛型函数,就是一个普通的函数支持类型参数的传入

你可能会疑惑为什么类型参数是S, 其实随便什么都可以,但是通常来说我们会用一个变量的第一个字母的大写来代表这个变量的类型:

  • T(for“T”ype)
  • E(for“E”lement)
  • K(for“K”ey)
  • V(for“V”alue)


7、泛型的类型范围限制

目前,在我们改进下的makeState()实现了只能输出数字state和只能输出字符串state。但是它也能实现输出布尔值。

// Creates a boolean-only state
const boolState = makeState<boolean>()
boolState.setState(true)
console.log(boolState.getState())

问题:那么我们要如何限制它就只能输入输出number和string类型呢?

方法:声明makeState()这个函数时,把类型参数<S>变为<S extends number | string>,这样就只能输入number或者string类型了

function makeState<S extends number | string>() {
  let state: S
  function getState() {
    return state
  }
  function setState(x: S) {
    state = x
  }
  return { getState, setState }
}
// 如果我传入boolean类型
const boolState = makeState<boolean>()
Type 'boolean' does not satisfy the constraint 'string | number'.


8、泛型的默认类型

现在每次调用makeState()时,我们可以任意传入<number> 或<string>类型,那怎么设置一个默认类型呢?

比如让下面两个语句起到相同的作用:

const numState1 = makeState()
const numState2 = makeState<number>()

其实和给函数参数设置默认值一样:

function makeState<S extends number | string = number>()

这样,变量state默认类型就是number了

const numState = makeState()
numState.setState(1)
console.log(numState.getState())


9、总结

泛型其实可以当作普通函数在声明时的一个参数,这个参数代表类型。
我们可以给函数值参数设置默认值,
也可以通过typescipt的泛型给函数类型参数设置默认值。

function regularFunc(x = 2)
regularFunc()
function genericFunc<T = number>()
genericFunc()

链接: https://fly63.com/article/detial/6730

TypeScript 泛型的通俗解释

在 TypeScript 中我们会使用泛型来对函数的相关类型进行约束。这里的函数,同时包含 class 的构造函数,因此,一个类的声明部分,也可以使用泛型。那么,究竟什么是泛型?如果通俗的理解泛型呢?

TypeScript泛型参数默认类型 和 新的 --strict 编译选项

TypeScript 2.3 增加了对声明泛型参数默认类型的支持,允许为泛型类型中的类型参数指定默认类型。接下来看看如何通过泛型参数默认将以下React组件从 JS (和JSX)迁移到 TypeScript (和TSX):

这些高阶ts内置泛型帮助类型,你用过几个

本文将简要介绍一些工具泛型使用及其实现, 这些泛型接口定义大多数是语法糖(简写), 你可以在 typescript 包中的 lib.es5.d.ts 中找到它的定义, 我们项目的版本

TypeScript的索引类型与映射类型,以及常用工具泛型的实现

相信现在很多小伙伴都在使用 TypeScript(以下简称 TS),在 TS 中除了一些常用的基本类型外,还有一些稍微高级一点的类型,这些就是我本次文章要讲的内容

一文读懂 TypeScript 泛型及应用

泛型是静态类型语言的基本特征,允许将类型作为参数传递给另一个类型、函数、或者其他结构。TypeScript 支持泛型作为将类型安全引入组件的一种方式。

秒懂 TypeScript 泛型工具类型!

如果你刚接触 TypeScript 不久,在阅读 TypeScript 内置工具类型的用法和内部实现的文章时,可能会看到 Pick 工具类型,对于该类型的语法你可能会感到陌生。

如何在 TypeScript 中使用泛型

泛型是静态类型语言的一个基本特征,允许开发人员将类型作为参数传递给另一个类型、函数或其他结构。当开发人员使他们的组件成为通用组件时,他们赋予该组件接受和强制执行在使用该组件时传入的类型的能力

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!