目录
概念
初识泛型
泛型类型
泛型类
泛型约束
泛型工具类型
Partial
Record
ReturnType
Pick
Exclude
概念
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
当我们定义一个变量不确定类型的时候有两种解决方式:
- 使用any
使用any定义时存在的问题:虽然 以 知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势 - 使用泛型
泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。
初识泛型
定义泛型:我们把要传入函数的参数类型设为一个类型变量 T ,它能够帮助我们捕获用户传入的类型,之后出现 T 的地方,都会被替换成用户传入的类型。
- 可以用两种方法使用。 第一种是,传入所有的参数,包含类型参数:
- 利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型:
function identity<T>(arg: T): T {
return arg;
}
function getFirst<T>(arr: T[]): T {
return arr[0];
}
console.log(identity<number>(10)); // 10
console.log(identity<string>('TS')); // TS
console.log(getFirst([1, 2, 3, 4])); // 1
console.log(getFirst(['a', 'b', 'c'])); // a
其实并不是只能定义一个类型变量,我们可以引入希望定义的任何数量的类型变量。比如我们引入一个新的类型变量 U
,用于扩展我们定义的 identity
函数:
function identity <T, U>(value: T, message: U) : T {
console.log(message);
return value;
}
console.log(identity<Number, string>(68, "Semlinker"));
泛型类型
<泛型变量名称>(参数1: 泛型变量, 参数2: 泛型变量, ...参数n: 泛型变量) => 泛型变量
我们还可以使用带有调用签名的对象字面量来定义泛型函数:
let foo: { <T>(arg: T): void };
foo = function <T>(arg: T): void {
console.log(arg);
}
foo(13); // 13
泛型接口
interface CreateArrayFunc<T> {
(length: number, value: T): Array<T>;
}
let createArray: CreateArrayFunc<any>;
createArray = function <T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
泛型类
泛型类看上去与泛型接口差不多。 泛型类使用( <>
)括起泛型类型,跟在类名后面。
类有两部分:静态部分和实例部分。 泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
class Animal<T> {
name: T;
constructor(name: T) {
this.name = name;
}
action<T>(say: T) {
console.log(say)
}
}
let cat = new Animal('cat');
cat.action('mimi')
泛型约束
我们定义一个接口来描述约束条件。 泛型可以通过 extends 一个接口来实现泛型约束,写法如:<泛型变量 extends 接口>
,
interface Person {
name: string;
age: number;
}
function student<T extends Person>(arg: T): T {
return arg;
}
student({ name: 'lili' });//类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性
student({ name: "lili", age: '11' });//不能将类型“string”分配给类型“number”
student({ name: "lili", age: 11 });
泛型工具类型
Partial
Partial<T>
的作用就是将某个类型里的属性全部变为可选项 ?
。
interface Person {
name: string;
age: number;
}
function student<T extends Person>(arg: Partial<T>): Partial<T> {
return arg;
}
student({
name: 'zs'
})
Record
Record<K extends keyof any, T>
的作用是将 K
中所有的属性的值转化为 T
类型。
interface PageInfo {
title: string
}
type Page = 'home' | 'about' | 'other';
const x: Record<Page, PageInfo> = {
home: { title: "xxx" },
about: { title: "aaa" },
other: { title: "ccc" },
};
ReturnType
ReturnType<T>
的作用是用于获取函数 T
的返回类型。
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<<T>() => T>; // {}
type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
type T4 = ReturnType<any>; // any
type T5 = ReturnType<never>; // any
type T6 = ReturnType<string>; // Error
type T7 = ReturnType<Function>; // Error
Pick
Pick<T, K extends keyof T>
的作用是将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型,示例:
interface Todo {
title:string,
desc:string,
time:string
}
type TodoPreview = Pick<Todo, 'title'|'time'>;
const todo: TodoPreview ={
title:'吃饭',
time:'明天'
}
Exclude
Exclude<T,U>
的作用是将某个类型中属于另一个类型的属性移除掉,示例:
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
const t: T0 = 'a'; //不能将类型“"a"”分配给类型“T0”