高级 Typescript 泛型教程

问题

Advanced Typescript Generics tutorial

假设我们有一个名为的类Attributes,它管理不同类型的属性——即EmployeeAttributesClientAttributes等。

type EmployeeProps = { name: string; salary: number; }; export class Attributes<T> { constructor(private data: T) {} get(key: string): string | number { return this.data[key]; } } const attrs = new Attributes<EmployeeProps>({ name: 'Tom', salary: 5000, }); // name is of type string or number because that's // what we have hardcoded as a return of the get method const name = attrs.get('name');

在上面的示例中,我们创建了一个 Attributes 类的实例,该实例传递了一个类型的泛型,该类型EmployeeProps具有 和 的键namesalary分别是字符串和数字类型。

get然后我们在实例上使用该方法并获取name 属性,但是我们在返回值上获得的类型是or stringnumber这意味着在使用类型保护来缩小范围之前,我们只能对其使用字符串和数字通用的操作向下的值的类型。

我们应该能够告诉 typescript name 变量应该是 string 类型,所以在这种情况下我们不必使用类型保护。

我们试图做的是限制get方法采用的参数是nameor salaryName 或 salary 是 type 中唯一有效的键T,这意味着我们只应该data
根据这些键从对象中获取值。

一旦我们将方法的参数限制get为类型的键之一,我们应该将方法T的返回值指定为与传入的键对应的类型get

因此,如果我们调用:

get('name');

类型中的name键对应的T类型是字符串,这就是get方法应该返回的类型。

解决方案——K extends keyof T generics

我们可以get在指定泛型类型K
只能是
T在初始化时传递给类的泛型类型的键之一的方法上使用泛型。

如果该get方法的参数仅被限制为作为类属性
T签名的接口的键之一,则该方法应返回– 来自 type 的键的类型datagetT[K]KT

type EmployeeProps = { name: string; salary: number; }; export class Attributes<T> { constructor(private data: T) {} get<K extends keyof T>(key: K): T[K] { return this.data[key]; } } const attrs = new Attributes<EmployeeProps>({ name: 'Tom', salary: 5000, }); // is now of type string const name = attrs.get('name'); // ERROR: Argument of type '"test"' is not assignable to parameter of type '"name" | "salary"'. const test = attrs.get('test');

如果你现在将鼠标悬停在 name 变量上,你应该看到它是类型的,
string因为我们已经指定该get方法返回T[K],这是一个对象查找,就像在 js 中一样 – 它查找K对象中键的值T– 在我们的案例是name来自类型
的键的
EmployeePropsstring

上面代码片段中的要点:

  • 的类型K只能是其中的一个关键T– 在我们的例子中name
    salary

  • 换句话说 – 我们只能get使用Tname
    salary

  • 对于get我们所说的返回值,查看T键的类型K
    并返回值。
    在我们的例子中,查看
    EmployeeProps
    的类型
    name并返回string

如何

我们之所以能够这样做,是因为在打字稿中字符串可以是类型例如,string “world”可以是“world”类型。

type World = 'world'; function logHello(message: World) { console.log(`Hello ${message}`); } // ERROR: Argument of type '"all"' is not assignable to parameter of type '"world"'. logHello('all'); logHello('world');

接口的键是 和 类型
EmployeeProps字符串,这允许我们将方法接收的参数限制为特定的键。一旦我们这样做了——我们所要做的就是将方法的返回值注释为类型中特定键的查找namesalarygetgetKEmployeeProps

发表评论