typescriptlang.org 在其中解释了声明类型参数时关键字“extends”的两种用法。

interface Lengthwise {
  length: number;
}
 
function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
  console.log(arg.length);
  return arg;
}
  1. 时。
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

  • 但是为什么在上面的第二个实例中使用“extends”关键字来约束泛型类型参数“Key”,因此它应该是类型参数“Type”的属性?为什么不使用关键字“in”作为“in keyof Type”,这更有意义? “因为那将是一个语法错误?


    – 


最佳答案
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"inKey"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 oneofextends_oneof。如果真的实现了,也许可以使用in(功能请求是关于功能,而不是语法,因此虽然很想“这应该是in”,但这有点离题)。但目前这根本不是语言的一部分。TypeScript 中只有一种泛型约束,意思是“任何子类型”,所以我们使用extends和 而不是in

该类型"a"是类型的子类型"a" | "b" | "c" | "d"

使用关键字extends表示类继承的语言这样做是因为继承类是被继承类的子类型。

keyof是将一种类型转换为另一种类型的运算符,它很容易Key extends TypeKeys处于那个位置。