问题
Advanced Typescript Generics tutorial
假设我们有一个名为的类Attributes
,它管理不同类型的属性——即EmployeeAttributes
、ClientAttributes
等。
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
具有 和 的键name
,salary
分别是字符串和数字类型。
get
然后我们在实例上使用该方法并获取name 属性,但是我们在返回值上获得的类型是or string
,number
这意味着在使用类型保护来缩小范围之前,我们只能对其使用字符串和数字通用的操作向下的值的类型。
我们应该能够告诉 typescript name 变量应该是 string 类型,所以在这种情况下我们不必使用类型保护。
我们试图做的是限制该get
方法采用的参数是name
or salary
。Name 或 salary 是 type 中唯一有效的键T
,这意味着我们只应该data
根据这些键从对象中获取值。
一旦我们将方法的参数限制get
为类型的键之一,我们应该将方法T
的返回值指定为与传入的键对应的类型。get
因此,如果我们调用:
get('name');
类型中的name
键对应的T
类型是字符串,这就是get
方法应该返回的类型。
解决方案——K extends keyof T generics
我们可以get
在指定泛型类型K
只能是T
在初始化时传递给类的泛型类型的键之一的方法上使用泛型。
如果该get
方法的参数仅被限制为作为类属性
T
签名的接口的键之一,则该方法应返回– 来自 type 的键的类型。data
get
T[K]
K
T
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
来自类型
的键的EmployeeProps
值string
。
上面代码片段中的要点:
-
的类型
K
只能是其中的一个关键T
– 在我们的例子中name
或salary
-
换句话说 – 我们只能
get
使用T
–name
或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
字符串,这允许我们将方法接收的参数限制为特定的键。一旦我们这样做了——我们所要做的就是将方法的返回值注释为类型中特定键的查找。name
salary
get
get
K
EmployeeProps