如何缩小派生 class 的只读 属性 的类型?

How can I narrow the type of a readonly property of a derived class?

我想扩展 Uint8Array 这样的 class 将类型限制在一定长度。例如:

class Bytes32 extends ByteArray {
    constructor() { super(32) }
    length: 32 = 32
}

但是,当我尝试实例化 class 时出现错误,因为 Uint8Array 上的 length 属性 只有 getter:

TypeError: Cannot set property length of [object Object] which has only a getter

如果我不在 class 声明中进行赋值,而只进行 length: 32,那么我会收到一个编译器错误,指出 length 从未被赋值。

有什么方法可以告诉 TypeScript(通过断言或通过证明)这个 class 的 length 属性 将 总是 32 因此它的类型应该从 number?

缩小到 32

我特别希望编译器知道缩小,这样我就可以拥有一个带有如下签名的函数:

function apple(data: ArrayLike<number> & { length: 32 })

这样的签名将增强我项目中的类型检查,而无需与任何特定的数字容器数组紧密耦合。唯一的要求是他们给我的东西必须(由编译器证明)恰好有 32 个元素。

因为您只是希望细化 length 成员的类型,特别是从 number32,并且只是对其进行初始化以满足类型检查,从而引入运行时错误,我们可以利用 Declaration Merging.

解决问题

具体来说,我们可以通过引入一个声明 属性 并与 class 本身合并的接口来将 length 的类型细化为 32

下面的技巧

interface Bytes32 {
  readonly length: 32;
}

class Bytes32 extends Uint8Array {
  constructor() { super(32); }
}

这项技术的应用范围很广,但也需要谨慎使用。