目录
4.4泛型
泛型是可以在保证类型安全的前提下,让函数等与多种类型一起工作,从而实现复用,常用于接口,class,函数中。
4.4.1泛型的基本使用
需求:怎么定义一个函数让用户传入的是什么类型,返回的就是什么类型。在这就要用到泛型。
当然用any也可以实现,但是用any不就失去了类型保护,那么我们用ts就没有任何意义了。
所以泛型可以在保证类型安全的情况下实现复用。
function func<T>(value:T):T{
console.log(value)
return value
}
func(1)
func("1")
func<boolean>(true)
用法:
- 在函数名称后添加<>,并添加类型变量,类型变量的名字可以是任意合法的变量名称,然后函数和参数的返回值类型就可以用这个类型变量来指定。
- 当传入数值时,该数值的类型就会被类型变量捕获到。
- 调用的时候也是一样,函数名<想传入的类型>(实参),或者是不指定具体了参数类型,让其进行类型推断,当编译器推断不出来的时候,我们就要手动指定了。能省就省。
4.4.2泛型约束
两种方式:
- 指定更加具体的类型
- 添加泛型约束
1.指定更加具体的类型
为什么需要泛型约束,就像前面所讲的类型断言as一样的,HTMLElement是一个大的类型,无法访问a标签的具体属性如href,要想访问a标签的具体属性,这个时候我们就要用到类型断言,在这里也是一样,泛型是一个打的类型,要想用到具体类型身上的属性,我们就要用到泛型约束。
function func<T>(value:T[]):T[]{
console.log(value.length)
return value
}
func([1,2,3])
2.添加泛型约束
//第一种方式
interface Ilength{length:number}
function funcc<T extends Ilength>(value:T):T{
console.log(value.length)
return value
}
funcc("123")
func({length:10})
func({length:10,name:"jack"})
//第二种方式
const funccc=<D>(value:D):D=>{
return value
}
funccc(3)
funccc('23')
这里的extends不是表示继承,而是表示我们传入的类型变量里面必须要满足Iength这个类型,也就是要有Ilength的这个属性,你只要有就可以 ,多了也没关系,进一步体现了接口的兼容性。
4.4.3多个泛型变量
泛型的类型变量可以有多个(用逗号分隔),且类型变量之间还可以约束(比如:第二个类型变量受第一个类型变量约束)
需求:创建一个函数用来获取对象中属性的值
keyof关键字:会接受一个对象类型,生成其键名称的联合类型(可能是字符串或数值),在下面这个例子中就是“key”|“age”
function funccc<T,key extends keyof T>(value:T,key:key){
console.log(value[key])
}
funccc({name:"ct",age:14},"name")
4.4.4泛型接口
泛型借口:接口也可以配合泛型来使用,以增加其灵活性,增加其复用性
interface Idfunc<T>{
id:(value:T)=>T
ids:()=>T[]
}
const obj:Idfunc<number>={
id(value){
return value
},
ids(){
return [1,2,3]
}
}
- 在接口名称后添加<>,并添加类型变量,类型变量的名字可以是任意合法的变量名称,然后在接口中所有成员都是可以使用这个类型变量的。
- 使用泛型接口时,我们必须显示指定具体类型,这一点是与在函数中使用泛型不同的地方。
其实数组就是泛型接口,我们在使用数组时,TS会根据数组的不同类型,来自动将类型变量设置为相应的类型。
4.4.5泛型类
泛型类:class可以配合类来使用
比如,React的class组件的基类Component就是泛型类,不同组件有不同的props和state。后面会讲。
//不能省略指定参数类型
class gen<T>{
defaultValue:T
add:(x:T,y:T)=>T
}
const myNum=new gen<number>()
//可以省略指定参数类型,有构造函数且构造函数中也用到了这个类型变量
class gen1<T>{
defaultValue:T
constructor(value:T){
this.defaultValue=value
}
add:(x:T,y:T)=>T
}
const myNum1=new gen1(10)
- 在class名称后添加<>,并添加类型变量,类型变量的名字可以是任意合法的变量名称,然后在class中所有成员都是可以使用这个类型变量的。
- 使用泛型class时, new 类名<想传入的类型>(),或者是不指定具体了参数类型,让其进行类型推断,当编译器推断不出来的时候,我们就要手动指定了。能省就省。
4.4.6泛型工具类型
泛型工具类型都是基于泛型实现的,并且是内置的,可以在代码中直接使用
主要学习以下几个
- Partial<Type>
- Readonly<Type>
- Pick<Type,Keys>
- Record<Keys,Type>
1.Partial<Type>
- 用来构造一个新类型,将Type的所有属性设置为可选的,结构是一样的,并不会改变原来的类型。
interface props{
name:string
age:number
}
type Ifprops=Partial<props>
2.Readonly<Type>
- 用来构造一个新类型,将Type的所有属性设置为为只读的,结构是一样的,并不会改变原来的类型。
interface props{
name:string
age:number
}
type Readonlyprops=Readonly<props>
3.Pick<Type,Keys>
- 从Type中选择一组属性用来构造新类型。
- Type表示选择谁的属性,Keys表示选择哪几个属性(多个就用联合类型组合起来),且选择的属性必须是Type中拥有的
interface props{
name:string
age:number
gender:string
}
type Selectprops=Pick<props,"name"|"age">
4.Record<Keys,Type>
- 构造一个对象类型,属性键为Keys,属性类型为Type
- Keys表明对象有哪些属性,Type表示对象属性的类型
interface props{
name:string
age:number
gender:string
}
type recordprops=