typescriptlang.org 在其中解释了声明类型参数时关键字“extends”的两种用法。
- 中。
interface Lengthwise {
length: number;
}
function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
console.log(arg.length);
return arg;
}
- 当时。
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a");
getProperty(x, "m");
// Error: Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.
在约束泛型类型时使用“extends”关键字是有意义的,这样它就应该具有扩展类型的属性和方法。(参见上面的第一种用法)。这也与 OOP 中继承中“extends”关键字的用法相匹配。
但是,为什么在上面的第二个实例中使用了“extends”关键字来约束泛型类型参数“Key”,以便它应该是类型参数“Type”的属性?为什么不使用关键字“in”作为“in keyof Type”,这更有意义?
提前感谢您的回答和评论!
注意:
我知道在声明映射类型时使用“in keyof”,如下所示。
type Optional<T> = {
[K in keyof T]?: T[K];
};
我的问题是,当泛型类型参数应该是另一个类型参数的属性时,为什么不使用相同的方法来约束它呢?
1
最佳答案
2
确实如此extends
,但不是in
,假设extends
您指的是“任何子类型”,而in
您指的是“单个成员”。(当然,您可能对这些关键字有不同的解释,但这会成为一个意见问题。)
对于,P in K
意味着P
将是的单个 成员K
。
来说不是必需的。P extends K
这意味着P
可以是的任何子类型K
,而不仅限于单个联合成员。在您的示例中,您可以这样写:
getProperty(x, Math.random() < 0.5 ? "a" : "d");
/* function getProperty<{
a: number;
b: number;
c: number;
d: number;
}, "a" | "d"> */
这里Key
推断为联合。根据上面的定义,"a" | "d"
类型"a" | "d"
不是“ in
” 。它只是一个子类型。 可以是 的任何子类型,包括完整联合,或,或,或 之类的奇特事物。当您调用 时,类型很可能会被推断为单个键,但这不是必需的,并且始终可以手动指定其他内容。"a" | "b" | "c" | "d"
in
Key
"a" | "b" | "c" | "d"
"a" | "d"
never
"b" & {oops: true}
getProperty()
Key
请注意,如果 TypeScript确实有“此类型参数必须是此联合的单个成员”的概念,那将非常有用,并且对此有一个长期存在的功能请求,网址为。这将允许您在泛型函数内缩小类型参数,这目前是不可能的(并导致在上有一个相关的功能请求):
interface Foo {
a: string,
b: number
}
function foo<K extends "a" | "b">(k: K): Foo[K] {
if (k === "a")
return "abc"; // error! k is "a" but K might be "a" | "b"
else
return 123; // error! k is "b" but K might be "a" | "b"
}
功能请求要求使用extends oneof
或extends_oneof
。如果真的实现了,也许可以使用in
(功能请求是关于功能,而不是语法,因此虽然很想“这应该是in
”,但这有点离题)。但目前这根本不是语言的一部分。TypeScript 中只有一种泛型约束,意思是“任何子类型”,所以我们使用extends
和 而不是in
。
|
该类型"a"
是类型的子类型"a" | "b" | "c" | "d"
。
使用关键字extends
表示类继承的语言这样做是因为继承类是被继承类的子类型。
keyof
是将一种类型转换为另一种类型的运算符,它很容易Key extends TypeKeys
处于那个位置。
|
–
|