写在前头:最近在学习ts的过程中,对泛型的这一概念感觉有点迷惑,在此之前,一直使用js来开发,引入ts之后,也只是any一把刷,为了避免成为anyscript工程师,痛定思痛,开始学习,记录一下自己的学习过程
什么是泛型
泛型:可以简单的理解为宽泛的类型,即可为不固定的某个类型,当然这个类型可以被限定在一个可选范围之类
单类型函数
function makeState() {
let state: number
function get() {
return state
}
function set(x: number) {
state = x
}
return { get, set }
}
let {get,set} = makeState()
set(2);
console.log(get())
在上面的示例里,每个参数还有返回值的类型都是事先指定好的,但是当我们又一个使用场景,譬如:传入一个其他类型的参数,代码必定会报错,那么,我们可以思考用什么方式来解决
使用联合类型改造
type params = string | number
function makeState() {
let state: params
function get() {
return state
}
function set(x: params) {
state = x
}
return { get, set }
}
let { get, set } = makeState()
set('hello');
console.log(get())
使用联合类型来改造,你最终会创建一个同时允许数字和字符串的状态,相反,我们希望makeState()支持创建两种不同的状态:一种是只允许数字,另一种是只允许字符串。
使用泛型来改造
function makeState<T>() {
let state: T
function get() {
return state
}
function set(x: T) {
state = x
}
return { get, set }
}
let { get, set } = makeState<string>()
set('hello');
console.log(get())
使用泛型来改造,相比使用联合类型,区别在于,联合类型允许我在makeState()之后,既可以传数值也可以传布尔,但是泛型不然,当我们在makeState<string>()之后,就注定,后面的set只能传string类型的值,number同理
受限制的泛型
如果不对泛型的类型做限制的话,泛型可以接收任意值,假设我们不希望makeState()能够创建非数字或非字符串的state(如布尔值),我们该怎么做呢,如下
function makeState<T extends string | number>() {
let state: T
function get() {
return state
}
function set(x: T) {
state = x
}
return { get, set }
}
let { get, set } = makeState<string>()
set('hello');
console.log(get())
这样,我们就只被允许在string和number两种类型中
makeState<boolean>()
这样就是错误的
默认值
如果我们希望在不给类型的时候,会有一个默认值,做容错处理的时候,我们可以这么做
function makeState<T extends string | number = number>() {
let state: T
function get() {
return state
}
function set(x: T) {
state = x
}
return { get, set }
}
let { get, set } = makeState()
// 这里没有指定类型,那么就是默认为number
set('hello');// error
set(1);// success