若是你:react
看到如下代码有没有很疑惑?typescript
function makePair< F extends number | string, S extends boolean | F >()
Java是和typescript同样支持泛型的,当我在大学开始学习Java的时候,我仍是一个菜鸟码农,遇到难点(好比泛型)就直接跳过,能学多少学多少,回寝室就LOL开黑。直到大学毕业我依旧没有理解泛型的概念闭包
可能你和我同样以为泛型很难,下面我会分享个人理解,但愿对你有所帮助。函数
makeState()
这个函数首先,我写了makeState这个函数,咱们会用这个函数来讨论泛型学习
function makeState() { let state: number function getState() { return state } function setState(x: number) { state = x } return { getState, setState } }
当你运行这个函数,咱们会获得getState()
和 setState()
这两个函数。code
让咱们来试一下,下面这段代码会打印出什么ip
const { getState, setState } = makeState() setState(1) console.log(getState()) setState(2) console.log(getState())
1
2
会打印出1和2,没那么难对吧?ci
Note: 若是你正在使用react,你可能会发觉,makeState()
和钩子函数useState()
很像。这里也涉及到了 闭包和ES6的 解构赋值
咱们把刚才给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
get
咱们能够用如下方法解决这个问题
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
咱们能不能修改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
的类型是数字,一个是字符串。
怎么用才能只写一个来实现呢?
这是咱们的第一个尝试:
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
是既能输出数字类型,又能输出字符串类型
接下来咱们的泛型要登场了:
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)
目前,在咱们改进下的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'.
如今每次调用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())
1
泛型其实能够看成普通函数在声明时的一个参数,这个参数表明类型。
咱们能够给函数值参数设置默认值,
也能够经过typescipt的泛型给函数类型参数设置默认值。
function regularFunc(x = 2) regularFunc()
function genericFunc<T = number>() genericFunc()