typescript - TypeScript 中扩展接口和相交接口的区别?
问题描述
假设定义了以下类型:
interface Shape {
color: string;
}
现在,考虑以下方法来为这种类型添加额外的属性:
延期
interface Square extends Shape {
sideLength: number;
}
路口
type Square = Shape & {
sideLength: number;
}
两种方法有什么区别?
而且,为了完整性和出于好奇,还有其他方法可以产生可比较的结果吗?
解决方案
是的,存在与您的方案相关或不相关的差异。
最重要的可能是具有相同属性键的成员在两种类型中的处理方式不同。
考虑:
interface NumberToStringConverter {
convert: (value: number) => string;
}
interface BidirectionalStringNumberConverter extends NumberToStringConverter {
convert: (value: string) => number;
}
上述extends
导致错误,因为派生接口声明的属性与派生接口中的键相同,但签名不兼容。
error TS2430: Interface 'BidirectionalStringNumberConverter' incorrectly extends interface 'NumberToStringConverter'.
Types of property 'convert' are incompatible.
Type '(value: string) => number' is not assignable to type '(value: number) => string'.
Types of parameters 'value' and 'value' are incompatible.
Type 'number' is not assignable to type 'string'.
但是,如果我们使用交集类型
type NumberToStringConverter = {
convert: (value: number) => string;
}
type BidirectionalStringNumberConverter = NumberToStringConverter & {
convert: (value: string) => number;
}
没有任何错误,并进一步给出
// And this is a good thing indeed as a value conforming to the type is easily conceived
const converter: BidirectionalStringNumberConverter = {
convert: (value: string | number) => {
return (typeof value === 'string' ? Number(value) : String(value)) as string & number; // type assertion is an unfortunately necessary hack.
}
}
const s: string = converter.convert(0); // `convert`'s call signature comes from `NumberToStringConverter`
const n: number = converter.convert('a'); // `convert`'s call signature comes from `BidirectionalStringNumberConverter`
这导致了另一个有趣的区别,interface
声明是开放式的。新成员可以在任何地方添加,因为interface
在同一声明空间中具有相同名称的多个声明被合并。
这是合并行为的常见用途
lib.d.ts
interface Array<T> {
// map, filter, etc.
}
数组平面图 polyfill.ts
interface Array<T> {
flatMap<R>(f: (x: T) => R[]): R[];
}
if (typeof Array.prototype.flatMap !== 'function') {
Array.prototype.flatMap = function (f) {
// Implementation simplified for exposition.
return this.map(f).reduce((xs, ys) => [...xs, ...ys], []);
}
}
请注意没有extends
子句存在,尽管在单独的文件中指定了接口都在全局范围内并按名称合并到具有两组成员的单个逻辑接口声明中。(对于语法略有不同的模块范围声明也可以这样做)
相比之下,存储在type
声明中的交集类型是封闭的,不能合并。
推荐阅读
- mysql - 如果 id 在另一个表中,Mysql 用值更新列
- reactjs - tsdx 和 babel 无法使用意外令牌构建典型的 TypeScript
- android - 如何在离子+反应+电容器项目中设置最低android版本支持?
- vba - 在我的所有 Outlook 邮件中查找并以斜体形式输入单词列表(在 a.txt 文件中列出)
- python - 通过 win32com (Python) 连接到 SAP 会话
- clang - 为什么我没有从 LLVM 获得精确的行/列调试信息
- php - 我的中间件返回 Not Found 而不是重定向“离开”
- android - Jetpack Compose 的方向
- python - 如何将列中的值映射到另一个数据框的另外两列并在两列上提取匹配值?
- r - 根据条件和按组计数创建新列