本文适合有一定ts基础但是又有点头晕的小白阅读.好久没那么努力果了,我愿称这篇笔记为,最强笔记!
什么是泛型?
泛型是可以在保证类型安全的前提下,让函数等于多种类型一起工作,从而实现复用.常用于:函数,接口,class中.
需求1: 创建一个函数,传入什么数据就返回该数据本身.
有人就甩出了这样一段代码:function fn(value:number): number {return value}
对,这样写确实可以实现一个基本功能.但是如果我想传入一个字符串的数据,阁下又该如何应对呢?
这时有人又说了,把:number改成:any不就行了. 确实也可以,但是这就失去了ts的类型保护,类型就变得不安全了.
那么如何解决呢?既然我们在声明函数的时候不能知道将来要传入的类型是什么,我们干脆在定义函数的时候先占个坑,然后调用函数的时候再去指定类型.这就是泛型.
泛型基本使用
function getData<T>(val:T) {
return val
}
console.log(getData<number>(123));
<>里面的内容就是我说的占位符,不一定叫T,叫其他的也可以. 后面val:T可以理解成把类型T给到val这个变量.
另外,在调用函数的时候可以让ts自动推断类型.
console.log(getData('123'));
泛型约束
需求2:在需求1的基础上.我想在返回数据之前打印一下他的length
function getData<T>(val: T) {
console.log(val.length);
return val
}
这时候,咱们的ts开始发脾气了.直接报出错误:类型“T”上不存在属性“length 那怎么办呢?
指定更加具体的类型或者用类型收缩(if之类的)!?
好像解决了问题,但是实际上并不太好.(这边不多赘述)
正确的方案应该是使用泛型约束.具体代码如下:
interface ILength {
length: number
}
function getData<T extends ILength>(val: T) {
console.log(val.length);
return val
}
在这段代码中,我们定义了一个叫ILength的接口.让T继承这个接口.因为ILength有length属性,所以T就一定具有length属性.
那有人就问了,如果我传一个number进来呢? ts:那你既然喜欢乱传我就给你报错呗
console.log(getData<number>(123)); //直接给你报错:**类型number不满足约束ILength(因为他没有length属性)**
定义多个泛型
需求3: 定义一个函数,传入对象和键,返回他的值.
有人可能这样写:
function getProps(obj: object,key: string) {
return obj[key]
}
恭喜你!又报错辣. 报错原因: 元素隐式具有 "any" 类型,因为类型为 "string" 的表达式不能用于索引类型 "{}"。在类型 "{}" 上找不到具有类型为 "string" 的参数的索引签名。
我透,这说的是什么鬼话啊??? 其实简单来说就是ts不知道obj身上是不是有key这个属性.ts可不管你知不知道,只要他不知道,那他就给你报错.
那怎么办呢?(陷入沉思) 简而言之就是建立obj和key之间的联系,如何建立呢,那就要用到keyof. 代码的具体实现如下:
function getProps<O,K extends keyof O>(obj: O,key: K) {
return obj[key]
}
解释一下.K extends keyof O的意思就是,这个泛型变量的取值继承了O的键. 既然有这样的限制了,那么key肯定是obj的键,所以一定能访问到,不会报错.
console.log(getProps({ name: 'zs', age: 20 }, 'age')); // 可以访问,打印出结果 20
console.log(getProps({ name: 'zs', age: 20 },'gender')); // 没有gender属性,所以不能访问,ts报错,打印undefined
泛型接口
大致是这样的:
interface Student<T>{
id: number
name: T
hobby: T[]
}
const s1: Student<string> = {
id: 123,
name: 'zs',
hobby: ['睡觉','吃饭','打游戏']
}
我前面讲了那么久,大家应该懂得都懂吧.
具体应用:
const arr1: number[] = [1, 2, 3]
const arr2: Array<number> = [1, 2, 3]
这两种写法实际上是一样的.我们一般都写第一种.实际上第二种方式就跟我上面写的两个demo类同了.为什么ts里面的数组能.出这么多属性.因为继承了Array这个接口.Array这个接口就是一个泛型接口.里面有length属性,pop方法啊,等等等等.(这个Array是ts帮我们定义的,所以我们直接用即可)
参考视频:(非常推荐大家去看看,ts入门全集) www.bilibili.com/video/BV1vX…
道长yyds.我一个讨厌ts的人都听的津津有味了属于是!!!