与 Typescript 中的 "extends" 关键字混淆
Confusion with the "extends" keyword in Typescript
想想 Typescript 中的以下代码行:
let x: 'a' | 'b' extends 'a' ? true : false;
我想知道 x
的类型是否正确,因为直觉上 'a' | 'b'
是 'a'
的 扩展 版本(至少我的直觉是这样说的)。我认为 extends
会像数学中的子集一样工作。 A extends B
当且仅当 B ⊆ A
.
不过,这里的实际类型x
好像是false
。我想我不明白 extends
关键字是如何工作的。
扩展检查实例的类型,不检查可能的变量。即使它有效,对于像 类 这样的复杂类型也毫无意义。如果您使用 String 检查它,它将是正确的。
let x: ('a' | 'b') extends String ? true : false;
输出将是;
true
您可以查看 https://www.typescriptlang.org/docs/handbook/2/conditional-types.html
中有关条件类型的文档
根据 Liskov Subsitution Principle,如果“Y extends X”或等同于“Y 是 X 的子类型”,那么只要请求符合类型 X 的值,就可以使用符合类型 Y 的值。这导致了一个违反直觉的结论:当涉及可能值的范围时,如果 Y 扩展 X,则 Y 比 X 更受约束。所有 Y 都是 X,但并非所有 X 都是 Y。
在您的示例中,因为 'a' | 'b'
可以是 'a'
或 'b'
,联合类型不会扩展类型 'a'
,因为 'b'
不会' 替代 'a'
。相反,'a' extends ('a' | 'b')
,因为所有匹配 'a'
的值都可以在请求 'a' | 'b'
的地方工作。
因此,A extends B
当且仅当 A ⊆ B
.
这在 TypeScript 中不太直观的一个原因是您的示例处理的是文字值的并集。我们从对象的角度来考虑这个问题可能更有意义,其中 {foo: number, bar: number} extends {foo: number}
。后者 {foo: number}
可以有任何类型的 bar
属性 或根本没有 bar
。前者 {foo: number, bar: number}
更具体,更受约束:不仅 foo
是一个数字,而且 bar
也是一个数字。这也匹配 class 或接口定义中 extends
的使用:subclass 或子接口 添加 属性和方法,其中 与超级class或超级接口相比,进一步限制了实例。
这也是: never
is the most constrained type because no actual values match it, so never
extends everything. The empty set is a subset of every set; the empty type never
is the subtype of every type and can be assigned to every other type。
type Foo = { foo: number };
type Bar = never extends Foo ? true : false; // true
想想 Typescript 中的以下代码行:
let x: 'a' | 'b' extends 'a' ? true : false;
我想知道 x
的类型是否正确,因为直觉上 'a' | 'b'
是 'a'
的 扩展 版本(至少我的直觉是这样说的)。我认为 extends
会像数学中的子集一样工作。 A extends B
当且仅当 B ⊆ A
.
不过,这里的实际类型x
好像是false
。我想我不明白 extends
关键字是如何工作的。
扩展检查实例的类型,不检查可能的变量。即使它有效,对于像 类 这样的复杂类型也毫无意义。如果您使用 String 检查它,它将是正确的。
let x: ('a' | 'b') extends String ? true : false;
输出将是;
true
您可以查看 https://www.typescriptlang.org/docs/handbook/2/conditional-types.html
中有关条件类型的文档根据 Liskov Subsitution Principle,如果“Y extends X”或等同于“Y 是 X 的子类型”,那么只要请求符合类型 X 的值,就可以使用符合类型 Y 的值。这导致了一个违反直觉的结论:当涉及可能值的范围时,如果 Y 扩展 X,则 Y 比 X 更受约束。所有 Y 都是 X,但并非所有 X 都是 Y。
在您的示例中,因为 'a' | 'b'
可以是 'a'
或 'b'
,联合类型不会扩展类型 'a'
,因为 'b'
不会' 替代 'a'
。相反,'a' extends ('a' | 'b')
,因为所有匹配 'a'
的值都可以在请求 'a' | 'b'
的地方工作。
因此,A extends B
当且仅当 A ⊆ B
.
这在 TypeScript 中不太直观的一个原因是您的示例处理的是文字值的并集。我们从对象的角度来考虑这个问题可能更有意义,其中 {foo: number, bar: number} extends {foo: number}
。后者 {foo: number}
可以有任何类型的 bar
属性 或根本没有 bar
。前者 {foo: number, bar: number}
更具体,更受约束:不仅 foo
是一个数字,而且 bar
也是一个数字。这也匹配 class 或接口定义中 extends
的使用:subclass 或子接口 添加 属性和方法,其中 与超级class或超级接口相比,进一步限制了实例。
这也是never
is the most constrained type because no actual values match it, so never
extends everything. The empty set is a subset of every set; the empty type never
is the subtype of every type and can be assigned to every other type。
type Foo = { foo: number };
type Bar = never extends Foo ? true : false; // true