🔍 搜索词
interface enforce, interface abstract, interface inherit
✅ 可实现性检查清单
- 这不会对现有的TypeScript/JavaScript代码造成破坏性的改变
- 这不会改变现有JavaScript代码的运行时行为
- 这可以在不根据表达式的类型发出不同的JS的情况下实现
- 这不是一个运行时特性(例如库功能、带有JavaScript输出的非ECMAScript语法、新的JS语法糖等)
- 这不是一个请求添加新实用类型的请求: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- 这个特性将与我们设计目标的其他部分一致: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐ 建议
允许接口,尤其是那些由库导出的接口,指定强制的用户定义类型缩小,会使许多情况变得更简单,消除开发者为了推迟类型解析而跳过的一些限制。
这可能看起来像这样:
interface Foo {
abstract bar: unknown;
baz: string;
}
const foo: Foo = {bar: 0, baz: "a"}; // errors - interface Foo has unset abstract property
interface Bar extends Foo {} // errors - property `bar` is missing
// all properties within Foo can be narrowed
interface Baz extends Foo {
bar: number;
baz: "hello" | "world";
}
对于一个更具体的例子,我们可以重新审视TS文档中的 Shape
示例:
interface Circle {
kind: "circle";
radius: number;
}
interface Square {
kind: "square";
sideLength: number;
}
type Shape = Circle | Square;
这很好,但它遇到了一个问题 - Circle和Square无法共享任何属性,因为我们已经从方程中删除了继承,所以面积和周长需要在每个或在共享的扩展接口上单独定义,如 BaseShape
。相反,我们可以坚持使用原始的继承模式,并在继承链的更深处进一步强制执行属性。
interface WithKind {
abstract kind: string;
}
interface Shape {
area: number;
perimeter: number;
}
interface ShapeWithKind extends Shape, WithKind {
kind: string;
}
interface Square extends Shape, WithKind {
kind: "square",
sideLength: number;
}
interface Circle extends Shape, WithKind {
kind: "circle",
radius: number;
}
interface Triangle extends Shape, WithKind { // error - missing property `kind`
sideLengths: [number, number, number];
}
当需要通过函数消费此内容时,我们可以指定是否需要 Shape
或 ShapeWithKind
,或者也许有些形状具有 family
属性,扩展 Shape
、 WithKind
和 WithFamily
。这在某种程度上让人想起了Dart的 abstract class mixin
,但只关注类型系统的影响,而忽略了该灵感的整个运行时影响。
📃 激励性示例
抽象类让你添加基本行为,以便程序员不必编写所有内容,同时仍然迫使他们遵循你的设计。新的接口属性允许在类型系统中实现相同的内容,改善消费者对你模块的体验,同时允许更强大的机制将类型解析推迟到使用点而不是定义点。
💻 用例
- 你打算用这个做什么?
我想用这个来强制接口的形状,而不需要在使用点提供所有类型信息。我的同事想要有效地编写interface Foo {...} satisfies Bar
,这是可以使用interface Foo extends AbstractFoo {...}
实现的。如果与 Add anabsent
type forbidding presence #55143 (甚至只是明智地使用never
底层类型)结合使用,你可以在继承接口方面应用完整的约束,即必须定义哪些成员以及哪些成员不能定义,这对于重载解析似乎尤其强大。 - 目前的方法存在哪些缺点?
我所知道的类似方法是使用虚拟实用类型,这意味着你要么将错误与接口签名分开,要么将一切都定义为类型别名并失去接口的价值。 - 你目前正在使用的解决方法是什么?
2条答案
按热度按时间deyfvvtc1#
出于某种原因,我认为您可以使用
implements
与接口一起使用,这将主要解决此用例,但显然是不允许的。u0njafvf2#
出于某种原因,我认为您可以使用
implements
与接口一起使用,这将主要解决这个用例,但显然这是不允许的。@fatcerberus - 是的,我基本上是在提议
implements
,但如果仅仅因为接口技术上没有实现任何内容就劫持那个关键字,那将会很奇怪