目录
泛型是什么?有什么作用
当我们定义一个变量不确定类型的时候有两种解决方式:
使用any
使用any定义时存在的问题:虽然 以 知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势
使用泛型
泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。
泛型用法:
在函数用法
function test <T> (arr:T):T{
console.log(arr);
return arr;
}
test<number>(11111);// 他返回值就是number类型的 11111
test<string | boolean>('justin')//它返回值是string类型的 justin
test<string | boolean>(true);//它返回值就是布尔类型的 true
在接口中使用泛型
interface Search {
<T,Y>(name:A,age:B):A
}
let fn:Search = function <A, B>(name: A, id:B):A {
console.log(name, id)
return name;
}
fn('jusin',111);//编译器就会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型
在类中使用泛型
class Justin<T> {
name:A
constructor(name: A){
this.name = name;
}
action<A>(say:A) {
console.log(say)
}
}
let arr= new Justin('arr');
arr.action('aaa')
泛型约束
使用接口约束泛型
interface Person {
name:string;
age:number;
}
function student<T extends Person>(arg:T):T {
return arg;
}
student({name:'aa'});//类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性
student({ name: "aa" , age:'11'});//不能将类型“string”分配给类型“number”
student({ name: "aa" , age:11});
数组泛型
let arr:Array<number> =[1,2,3] === let arr:number[]=[1,2,3]
一些场景的使用:
写一个函数,这个函数会返回任何传入的值。
eg:不用泛型的话,这个函数可能是下面这样:
function identity(arg: number): number {
return arg;
}
如果我们要编写框架,就要考虑到各种返回值的情况,于是可能就会有这样的代码:
type idBoolean = (arg: boolean) => boolean;
type idNumber = (arg: number) => number;
type idString = (arg: string) => string;
很明显,我们的这些代码逻辑是相同的,但是由于需要,我们不得不写 n
遍这样的逻辑。
有些小伙伴可能会说,我们可以使用any
类型来定义函数:
function identity(arg: any): any {
return arg;
}
使用any
类型会导致这个函数可以接收任何类型的arg
参数,这样就丢失了一些信息:传入的类型与返回的类型应该是相同的。
所以为了解决算法的复用,我们引入了泛型的概念。如下所示:
function identity<T>(arg: T): T {
return arg;
}
我们给identity添加了类型变量T
。 T
帮助我们捕获用户传入的类型(比如:number
),之后我们就可以使用这个类型。
接下来我们就可以通过这样的语法调用 identity
函数。
identity<string>('hellojustin');
可以在什么地方使用泛型
可以在任何支持调用值的地方实现泛型。
// 作用域覆盖整个签名
1、type Filter<T> = {
(array: T[], f: (item: T) => boolean): T[]
}
// 作用域覆盖函数调用期
2、type Filter = {
<T>(array: T[], f: (item: T) => boolean): T[]
}
// 3 是 2 的简写形式
3、type Filter = <T>(array: T[], f: (item: T) => boolean): T[]
// 4 是 1 的简写形式
4、type Filter<T> = (array: T[], f: (item: T) => boolean): T[]
// 具名函数调用签名
5、function Filter<T>(array: T[], f: (item: T) => boolean): T[] { ...... }
泛型默认类型
泛型在定义的时候可以指定默认类型。
以 MyEvent 来举例
type MyEvent<T> = {
target: T;
type: string;
}
为了给事先不知道 MyEvent 将会绑定何种元素的情况提供便利,我们可以给 T 指定一个默认的类型。
type MyEvent<T = HTMLElement> = {
target: T;
type: string;
}
泛型工具类型
Partial
partial<T>的作用就是将某个类型中的属性全部变为可选项?
示例:
interface Person {
name:string;
age:number;
}
function student<T extends Person>(arg: Partial<T>):Partial<T> {
return arg;
}
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" },
};
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 ='b';
4.5 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