在前端开发中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。这时候ts的泛型就起到了关键的作用。
一:泛型: 基本用法
(1): 常规使用
现在有个需求:封装一个方法,接收一个参数(number类型),return一个相同类型的result。
const indentify1 = (args: number): number => {
return args;
}
如果接收的类型是number或者string呢?
const indentify2 = (args: number | string): number | string => {
return args;
}
如果参数类型越来越多怎么处理?泛型可以解决。
const indentify3 = <T>(args: T): T => {
return args; // T类似一个变量保证入参和出参类型一致。
}
泛型起到约束作用。泛型不只可以提供一个。
const indentify4 = <T, U>(args: T, mes: U): T => {
return args; // 提供一个T和U泛型,声明入参类型,指定返回结果类型。
}
(2): 泛型接口
如上indentify4函数,若是函数返回的是多类型集合,泛型如何处理?
方法一:返回类型集合
const indentify5 = <T, U>(args: T, mes: U): [T,U] => {
return [args, mes]; // 约束太多,外层对泛型的约束
}
方法二: 泛型接口
可以提供一个接口,把接口内的参数变为泛型。举个🌰: 定义一个person函数,接收姓名,年龄,性别,是否结婚。最后return。
interface IPersonView<T, U, V> {
name: T,
age: U,
sex: T,
isMarray: V
}
const per = <T, U, V>(name: T, age: U, sex: T, isMarray: V):IPersonView<T, U, V> => {
let result: IPersonView<T, U, V> = {
name, age, sex, isMarray
}
return result;
}
可以看出使用泛型接口可以很友好的解决这些问题。便于维护和统一。
二:常用的操作符
(1): extends
很简单就是继承的意思,让一个类型变量继承我们定义好的类型。在泛型约束中起到了很大的作用。(之后会说到泛型约束)
(2): keyof
该操作符可以用于获取某种类型的所有键,其返回类型是联合类型。举个🌰:
interface Person {
name: string;
age: number;
isMarray: boolean;
}
type per1 = keyof Person // string | number | boolean
三:泛型约束
有时我们可能希望限制每个类型变量接受的类型数量,这就是泛型约束的作用。起到对类型变量限制作用。
举个🌰:处理字符串或数组时,我们会假设 length 属性是可用的。当我们使用函数并尝试输出参数的长度,会出现一些问题。
const indentify5 = <T>(args: T):T => {
console.log(args.length); // // 类型“T”上不存在属性“length"
return args;
}
出现这个问题的原因是,因为ts编译器不知道,不能识别T上是否含有某个属性。我们可以定义一个类型,让类型变量extends。
interface ILength {
length: number // 定义一个接口包含length
}
const indentify6 = <T extends ILength>(args: T):T => {
console.log(args.length); // number
return args;
}
当然了:对上面这种情况我们也可以定义数组类型来解决。
const indentify7 = <T>(args: T[]): T[] => {
console.log(args.length);
return args;
}
const indentify8 = <T>(args: Array<T>): Array<T> => {
console.log(args.length);
return args;
}
我们也可以通过keyof来确实对象上的键是否存在。举个🌰:
声明一个类型接口。
interface Ip {
name: string,
sex: string,
age: number
}
// 通过 keyof 操作符,我们就可以获取指定类型的所有键,之后我们就可以结合extends约束
//即限制输入的属性名包含在 keyof 返回的联合类型中
const indentify9 = <IPerson, K extends keyof Ip>(obj: Ip , key: K): Ip[k] {
return obj[key];
}
泛型工具
(1): Partial
将某个类型里的所有属性变成非必需属性。
type Partial<T> = {
[P in keyof T]?: T[P]; // 把!变成?
};
举个🌰:
interface IPerson {
name: string,
age: number
}
Partial<IPerson> === interface IPerson {
name?: string | undefined,
age: number | undefined
}
(2): Exclude
将T中某些属于U的类型移除掉
type Exclude<T, U> = T extends U ? never : T;
type T = Exclude<"a" | "b" | "c", "a"> // "b" | "c"
(3): ReturnType
ReturnType 的作用是用于获取函数 T 的返回类型。
type T1 = ReturnType<() => String> // string
type T2 = ReturnType<(args: String) => void> // void
type T3 = ReturnType<<T>() => T>; // {}
以上就是一些简单的使用,有不足欢迎大家指出。