type Handlers = {
[name: string | number]: () => void
}
type H1 = {
"click": () => void
}
interface H2 {
"click": () => void
}
type A = H1 extends Handlers ? 'yes' : 'no' // yes
type B = H2 extends Handlers ? 'yes' : 'no' // no
TSC v5.1.6.
虽然H1和H2具有相同的结构,但我得到A是“是”而B是“否”。
extends 子句中的类型和接口似乎有些区别。 typescript手册我看了两遍,没找到相关解释。
不知道是否和TSC的一些底层逻辑有关?
Interface的类型检查比Type更严格吗?
type 可以表示很多种类型,包括原始类型、并集、交集等
接口更注重对象形状定义,可以通过其他接口进行扩展。
type 在条件类型中按预期工作,条件类型检查指定类型是否可分配给另一个类型。
条件类型中的接口表现不同。 TypeScript 的条件类型使用结构兼容性进行检查,并且接口是开放式的。
H1 扩展了 Handlers,因为它与结构完全匹配,因此输入 A = 'yes'。 由于类型和接口之间的行为差异,H2 不会在条件类型上下文中扩展处理程序,因此输入 B = 'no'。
示例:-
类型:-
type H1 = {
"click": () => void
}
type A = H1 extends Handlers ? 'yes' : 'no' // yes
接口:-
interface H2 {
"click": () => void
}
type B = H2 extends Handlers ? 'yes' : 'no' // no
interface H2Extended extends H2 {
"hover": () => void
}
let h2Var: H2;
let h2ExtVar: H2Extended;
h2Var = h2ExtVar; // This is valid
在 TypeScript 中,
type
和 interface
都可以定义对象形状,但它们有一些细微的区别。在您的示例中,问题的出现是因为它们如何与 extends
子句交互。
当您将
type
与 extends
一起使用时,TypeScript 会检查正在检查的类型(左侧)是否符合与其比较的类型(右侧)的约束。在你的例子中,H1扩展了Handlers
,因为Handlers
允许任何字符串或数字作为键,并且H1有一个匹配的属性"click"
。
但是,对于像
interface
这样的 H2
,即使它与 H1
具有相同的结构,TypeScript 也不会将其视为扩展 Handlers
。这种行为源于内部 TypeScript 规则,这些规则使得两者在某些情况下的行为略有不同。
简单来说,
type
和 interface
都定义了对象形状,但是在处理 extends
和映射类型时,它们的行为可能会因 TypeScript 内部评估它们的方式而有所不同。根据您的代码需求选择正确的方法非常重要。