| 什么是泛型
泛型是可以在保证类型安全的前提下,让函数可以多种类型一起工作实现复用
泛型常用于函数、接口、类中
为了让函数可以接受任意类型,为什么不将参数改为any呢?
使用any会失去TS的类型保护,类型不安全,这样就本末倒置了
在其他编程语言中,泛型都是用来实现可复用组件的主要工具之一
// 使用泛型来创建一个函数
function id<Type>(value: Type): Type {
return value;
}
// 调用泛型函数
const test1 = id<number>(1);
const test2 = id<string>('1');
console.log(test1); // 1
console.log(test2); // '1'
// 简写
const test1 = id(1); // 1
const test2 = id('1'); // '1'
| 泛型约束
默认情况下,因为泛型函数的变量Type可以代表多个类型,这就导致无法访问任何属性
如无法保证当前值一定存在length属性
此时需要使用泛型约束来指定类型取值范围
替换方式
- 指定更加具体的类型
比如将类型改为Type[],即Type类型的数组,因为数组必然有length属性
function id<Type>(value: Type[]): Type[] {
console.log(value.length);
return value;
}
- 添加约束
①创建一个接口用来提供length属性
②通过extends来使用该接口,表面传入的参数必须要有length属性
interface ILength {
length: number;
}
function id<Type extends ILength>(value: Type): Type {
console.log(value.length);
return value;
}
id([1]); // 必须要有length属性,比如数组
| 多个泛型变量
泛型的类型变量可以有多个,并且变量之间可以约束
示例
function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}
let person = {
name: 'lzz',
age: 18,
};
console.log(getProp(person, 'age'));
示例中使用两个变量类型,Type和Key
keyof关键字用于两个变量之间的约束,Key只能是Type中的属性
| 泛型之于接口
接口也可以配合泛型使用,增加灵活性、复用性
在接口后面添加<类型变量>即可
interface idFunc<Type> {
id: (value: Type) => Type;
ids: () => Type[];
}
// 指定类型为number
let obj: idFunc<number> = {
id(value) {
return value;
},
ids() {
return [1, 2, 3]; // number数组
},
};
事实上,ts中的数组也是一个泛型接口
当我们使用数组时,TS会根据数组的不同类型来自动将类型变量设置为相应类型
| 泛型之于类
class也可以配合泛型来使用
比如React的class组件的基类Component就是泛型类,不同组件有不同的props和state
创建泛型类
class GenericNumber<Type> {
defaultValue: Type;
add: (a: Type, b: Type) => Type;
}
let myNumber = new GenericNumber<string>(); // 可传类型,也可省略
myNumber.defaultValue = '10'
myNumber.add = (a, b) => a + b;
| 泛型工具
TS内置了一些常用工具类型,来简化TS中常见操作
常见工具类型有
- Partial
- Readonly
- Pick
- Record
Partial 创建可选
用来构建一个类型,将Type的所有属性设置为可选
比如有一个接口A,你要创建一个结构与接口A一样类型B,但属性是可选的,就用Partial
interface A {
id: number;
name: string;
}
type B = Partial<A>;
let test: B = {
id: 1 // id或name属性可选
};
Readonly 只读
顾名思义,就是将Type所有属性设置为只读
interface A {
id: number;
name: string;
}
type B = Readonly<A>;
let test: B = {
id: 1,
name: 'zz',
};
test.id = 2 // 报错,Cannot assign to 'id' because it is a read-only property.
Pick 挑选属性
从Type中选择一组属性来构造新的Type
Pick<选择谁的属性, '属性1' | '属性2' >
interface A {
id: number;
name: string;
age: number;
}
type B = Pick<A, 'id' | 'age'>;
let test: B = {
id: 1,
age: 18,
};
Record 构造对象类型
构造一个对象类型,属性键为Keys, 属性类型为Type
示例,构建一个含有age,name,id,类型全为string的对象
type Obj = Record<'age' | 'name' | 'id', string>;
let person: Obj = {
id: '233',
age: '1',
name: 'zz',
};