TS中的泛型
Posted xianghong_yang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TS中的泛型相关的知识,希望对你有一定的参考价值。
文章目录
一、泛型是什么?有什么作用
当我们定义一个变量不确定类型的时候有两种解决方式:
- 使用any
使用any定义时存在的问题:虽然 以 知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势 - 使用泛型
泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。
二、泛型用法
2.1 在函数中使用泛型
function test <T> (arg:T):T
console.log(arg);
return arg;
test<number>(111);// 返回值是number类型的 111
test<string | boolean>('hahaha')//返回值是string类型的 hahaha
test<string | boolean>(true);//返回值是布尔类型的 true
使用方式类似于函数传参,传什么数据类型,T就表示什么数据类型, 使用表示,T也可以换成任意字符串。
2.2 在接口中使用泛型
// 注意,这里写法是定义的方法哦
interface Search
<T,Y>(name:T,age:Y):T
let fn:Search = function <T, Y>(name: T, id:Y):T
console.log(name, id)
return name;
fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型
2.3 在类中使用泛型
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')
三、泛型约束
3.1使用接口约束泛型
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);
3.2 数组泛型
let arr:Array<number> =[1,2,3] === let arr:number[]=[1,2,3]
四、泛型工具类型
4.1 Partial
partial<T>
的作用就是将某个类型中的属性全部变为可选项?
示例:
interface Person
name:string;
age:number;
function student<T extends Person>(arg: Partial<T>):Partial<T>
return arg;
4.2 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" ,
;
4.3 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:'明天'
4.4 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
暂时先了解这么多,后续继续补充…
关于TS的泛型
1. 泛型是什么
泛型,顾名思义,就是可以适用于多个类型,使用类型变量比如T帮助我们捕获传入的类型,之后我们就可以继续使用这个类型。
如下定义了一个identity泛型函数,<T>添加了类型变量T,它就可以帮助捕获我们传入的变量value的类型,然后再次使用T作为返回值类型,这样就约束了参数类型和返回值类型是相同的了。
function identity <T>(value: T) : T {
return value;
}
2. 泛型类型和泛型接口
const myIdentity: <T>(arg: T) => T = identity;
泛型类型和非泛型类型没有什么区别,只是传入了类型参数。
我们还可以使用对象字面量的形式来声明函数类型:
const myIdentity: { <T>(arg: T): T } = identity;
这样就引入了泛型接口:
interface GenericIdentityFn {
<T>(arg: T): T;
}
const myIdentity: GenericIdentityFn = identity;
再进一步把类型变量T作为接口的参数,使用接口的时候再传入类型参数,就锁定了函数中使用的类型:
interface GenericIdentityFn<T> {
(arg: T): T;
}
const myIdentity: GenericIdentityFn<number> = identity;
3. 泛型类
在类名后面跟上类型变量,就可以在类中使用这些泛型类型。
class GenericPerson<T, U> {
name: T;
getAge: (age: U) => U;
}
let person = new GenericPerson<string, number>();
person.name = \'Jane\';
person.getAge = function (x) { return x; };
person.getAge(2);
4. 何时使用泛型
当接口、函数或类要处理多种数据类型并且在其中多个地方使用该类型的时候。
5. 泛型约束
通常用接口来描述约束条件,用extends实现约束。
// 传入符合约束类型的值,必须包含length属性
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
// 通过 K extends keyof T 确保参数 key 一定是对象中含有的键,这样就不会发生运行时错误
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
6. 泛型条件类型
条件类型会以一个条件表达式进行类型关系检测,从而在两种类型中选择其一:
T extends U ? X : Y
通常会结合推断关键字infer来使用:
type ParamType<T> = T extends (...args: infer P) => any ? P : T;
这样就可以实现类型抽取,如果T可以赋值给(...args: infer P) => any,那么返回参数P,否则返回T本身的类型。
以上是关于TS中的泛型的主要内容,如果未能解决你的问题,请参考以下文章