TypeScript 允许接口声明继承者必须定义的成员

rbl8hiat  于 3个月前  发布在  TypeScript
关注(0)|答案(2)|浏览(33)

🔍 搜索词

interface enforce, interface abstract, interface inherit

✅ 可实现性检查清单

⭐ 建议

允许接口,尤其是那些由库导出的接口,指定强制的用户定义类型缩小,会使许多情况变得更简单,消除开发者为了推迟类型解析而跳过的一些限制。
这可能看起来像这样:

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];
}

当需要通过函数消费此内容时,我们可以指定是否需要 ShapeShapeWithKind ,或者也许有些形状具有 family 属性,扩展 ShapeWithKindWithFamily 。这在某种程度上让人想起了Dart的 abstract class mixin ,但只关注类型系统的影响,而忽略了该灵感的整个运行时影响。

📃 激励性示例

抽象类让你添加基本行为,以便程序员不必编写所有内容,同时仍然迫使他们遵循你的设计。新的接口属性允许在类型系统中实现相同的内容,改善消费者对你模块的体验,同时允许更强大的机制将类型解析推迟到使用点而不是定义点。

💻 用例

  1. 你打算用这个做什么?
    我想用这个来强制接口的形状,而不需要在使用点提供所有类型信息。我的同事想要有效地编写 interface Foo {...} satisfies Bar ,这是可以使用 interface Foo extends AbstractFoo {...} 实现的。如果与 Add an absent type forbidding presence #55143 (甚至只是明智地使用 never 底层类型)结合使用,你可以在继承接口方面应用完整的约束,即必须定义哪些成员以及哪些成员不能定义,这对于重载解析似乎尤其强大。
  2. 目前的方法存在哪些缺点?
    我所知道的类似方法是使用虚拟实用类型,这意味着你要么将错误与接口签名分开,要么将一切都定义为类型别名并失去接口的价值。
  3. 你目前正在使用的解决方法是什么?
deyfvvtc

deyfvvtc1#

出于某种原因,我认为您可以使用implements与接口一起使用,这将主要解决此用例,但显然是不允许的。

u0njafvf

u0njafvf2#

出于某种原因,我认为您可以使用 implements 与接口一起使用,这将主要解决这个用例,但显然这是不允许的。
@fatcerberus - 是的,我基本上是在提议 implements ,但如果仅仅因为接口技术上没有实现任何内容就劫持那个关键字,那将会很奇怪

相关问题