【TS】TypeScript 泛型

文章目录

泛型的写法

【函数的泛型写法】

【类的泛型写法】

【接口的泛型写法】

【类型别名的泛型写法】

泛型参数默认值

泛型参数约束

方法一: 为类型参数指定更加具体的类型

方法二:为泛型参数指定接口约束收缩类型

 【keyof 关键字】

泛型类型工具

【Partial】

【Readonly】

【Pick】

【Record】


泛型是可以在保证类型安全前提下,让函数、类等与多种类型一起工作,从而灵活实现复用。常用于:函数、接口、class 中。

泛型的写法

变量名称的后面添加 < >(尖括号),尖括号中添加类型参数(类型变量)Type。该类型参数相当于一个类型容器,能够捕获用户提供的类型(具体是什么类型由用户使用该变量时指定)。这里的类型参数 Type,可以是任意合法的变量名称。

【函数的泛型写法】

// 使用泛型来创建一个函数:
function id<Type>(value: Type): Type {
    return value
}

// 调用泛型函数:
const num = id<number>(10); // 以number类型调用,变量类型Type为number

const str = id<string>('a'); // 以string类型调用,变量类型Type为string

【类的泛型写法】

下面代码中传入了两个类型参数 <Type, vType> ,多个类型参数之间使用逗号( , )分隔。

// 定义泛型类
class C<Type, vType> {
    value!: Type;
    add!: (x: Type, y: Type) => vType;
}
// 实例化泛型类
let foo = new C<number, string>();
// 给类成员赋值
foo.value = 0;
foo.add = function (x, y) {
    return x + "" + y;
};

【接口的泛型写法】

// 定义泛型接口
interface User<Type, nType> {
    name: Type;
    age: nType;
    detail: () => Type;
}
// 使用
let box: User<string, number> = {
    name: "小七",
    age: 20,
    detail() {
        return this.name + this.age;
    }
};

数组也是泛型接口

【类型别名的泛型写法】

// 定义类型别名
type Container<T> = { value: T };
// 使用
const a: Container<number> = { value: 0 };

案例:递归实现实现树形结构

// 定义树形结构
type Tree<T> = {
    value: T;
    left: Tree<T> | null;
    right: Tree<T> | null;
};

泛型参数默认值

在 JS 中可以为参数设置默认值,TS 中同样也可以为泛型参数设置默认值,写法也与 JS 相同。

class Arr<Type = string> {
    list: Type[] = [];
}

let arr = new Arr(); // 未传入类型参数,默认为string类型

arr.list = ['a','b']; // 正确
arr.list = [1,2,3,4]; // 报错

泛型参数约束

默认情况下,泛型的类型参数 Type 可以代表任意类型,这会导致变量无法访问任何属性。就需要为泛型添加约束来收缩类型(收缩类型取值范围)。

下面示例中,Type 可以代表任意类型,无法保证一定存在 length 属性,比如 number 类型。

function id<Type>(value: Type): Type {
    console.log(value.length); // --报错
    return value
}

方法一: 为类型参数指定更加具体的类型

下面示例中,将 value 的类型指定为 Type[] (Type 类型的数组),数组一定存在 length 属性,因此便可以访问 value.length 。

function id<Type>(value: Type[]): Type[] {
    console.log(value.length); // 正确
    return value
}

方法二:为泛型参数指定接口约束收缩类型

下面示例中,定义了接口 ILength ,要求必须提供 length 属性。泛型参数通过 extends 关键字使用该接口,为泛型的类型参数添加约束。·        

interface ILength {
    length: number
}
function id<Type extends ILength>(value: Type): Type {
    console.log(value.length);
    return value
}

id(['a', 'c']); // 传入数组 --正确
id('abc'); // 传入字符串 --正确
id({ length: 10, name: 'jack' });  // 传入对象,对象中有length属性 --正确

id(123); // 传入数字,没有length属性  -- 错误

该方法也可简写为

function id<Type extends { length: number }>(value: Type): Type {
    console.log(value.length);
    return value
}

 【keyof 关键字】

keyof 关键字接收一个对象类型,生成由其属性名作为字面量类型组成的联合类型

下面示例中,先使用 typeof 关键字,获取 obj 对象的类型信息,再使用 keyof 关键字,获取 obj 对象的属性名,并生成联合类型。

let obj = { name: 'jack', age: 18, sex: 'male' };
let obj2: keyof typeof obj;

案例:向函数中传入两个参数,使第二个参数受第一个参数约束。

下面示例中,参数 Key extends keyof Type,使用 keyof 关键字,获取第一个参数 Type 对象中的属性名,并生成联合类型。再通过 extends 关键字使用联合类型作为第二个参数 Key 的约束条件。

function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
    console.log(obj[key]);
}

getProp({ name: 'jack', age: 18 }, 'age'); // 18
getProp({ name: 'jack', age: 18 }, 'name'); // jack

getProp(18, 'toFixed'); // ƒ toFixed() { [native code] }
getProp(['a', 'b'], 'length'); // 1

泛型类型工具

【Partial】

Partial<Type> 用来构造(创建)一个类型,将 Type 的所有属性设置为可选

下面示例中,构造出来的新类型 PartialProps 结构和 Props 相同,但所有属性都变为可选的。

// 定义类型Props
type Props =  {
  id: string
  children: number[]
}
// Partial<Type>
type PartialProps = Partial<Props>

let p1: Props = { id: '' }; // 缺少children属性 --报错

let p2: PartialProps = { id: '' }; // 所有属性均为可选属性 --正确

【Readonly】

Readonly<Type> 用来构造一个类型,将 Type 的所有属性都设置为 readonly(只读)。

下面示例中,构造出来的新类型 ReadonlyProps 结构和 Props 相同,但所有属性都变为只读的。

// 定义类型Props
type Props = {
    id: string
    age: number
}
// Readonly<Type>
type PartialProps = Readonly<Props>

let p1: Props = { id: 'a', age: 18 }; 
p1.age = 20; // 正常使用

let p2: PartialProps = { id: 'b', age: 18 };
p2.age = 20; // 所有属性均为只读属性 --报错

【Pick】

Pick<Type, Keys> 从 Type 中选择一组属性来构造新类型。

Pick 工具类型有两个类型参数:1 表示选择谁的属性 2 表示选择哪几个属性。

第二个类型参数 Keys 传入的属性只能是第一个类型参数中存在的属性。

下面示例中,构造出来的新类型 PickProps,只有 id 和 title 两个属性类型。

// 定义类型Props
type Props = {
    id: number
    name: string
    age: number
}
// Pick<Type, Keys>
type PartialProps = Pick<Props, 'age' | 'name'>

let p1: Props = { id: 1, name: 'a', age: 18 };
p1.age = 20; // 正常使用

let p2: PartialProps = { id: 2, name: 'b', age: 18 };
p2.age = 20; // PartialProps中只有name和age属性 --报错

【Record】

Record<Keys,Type> 构造一个对象类型,属性键为 Keys,属性类型为 Type。

Record 工具类型有两个类型变量:1 表示对象有哪些属性 2 表示对象属性的类型。

场景:创建有多个属性的对象,且这些属性均为同一类型

下面示例中,构建的新对象类型 RecordObj 表示:这个对象有三个属性分别为a/b/c,属性值的类型都是 string。

// Record<Keys,Type>
type RecordObj = Record<'a' | 'b' | 'c', string>
// 等价于
// type RecordObj = {
//   a: string
//   b: string
//   c: string
// }

let obj: RecordObj = {
  a: 'a',
  b: 'b',
  c: 'c'
}

更多泛型类型工具https://wangdoc.com/typescript/utility#returntypetype

TypeScript 教程——阮一峰·著

TypeScript 中文网

TypeScript 官网

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值