使打字稿接口扩展另一个接口,不包括已定义的键

Make typescript interface extend another interface excluding keys already defined

对于我的 iPhone 上的一些 hacky 脚本( 不是 我会为生产编写的代码),我经常发现自己将 string 视为 string[](字符数组)。由于在 phone 上打字比在键盘上打字慢得多,而且考虑到 57 个字符宽的屏幕尺寸,字符非常宝贵,因此我编写了一些代码,采用 Array.prototype 的所有方法,将其映射到Array.from(this)[fn],并将其附加到 String.prototype (如果尚不存在)。比如我要.slice()还是return一个string,而不是string[].

Object.entries(
  Object.getOwnPropertyDescriptors(Array.prototype)
)
  .filter(([n, d]) =>
    !(n in String.prototype) &&
    typeof d.value === 'function'
  )
  .forEach(([n]) =>
    String.prototype[n] = function (...args) {
      return Array.from(this)[n](...args)
    }
  )

现在我可以 运行 'abc'.filter(x => x !== 'b') 并接收 ['a', 'c']。万岁。

现在我想编写更新后的 interface String 而无需手动复制 Array<T> 中的每个有效声明。 (有时 play.js 会读取 .d.ts 文件。)

我最好的尝试是引入循环类型引用,这并不让我感到惊讶。

type MethodNames<T> = {
  [K in keyof T & string]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T & string];

type MethodsOf<T> = {
  [K in MethodNames<T>]: T[K];
};

type CharArray = Omit<MethodsOf<Array<string>>, keyof string>;

declare global {
  interface String extends CharArray {}
}

export {};

TS Playground

直到我 String 扩展 CharArray,一切正常。 CharArray 有正确的方法。添加扩展后,CharArray 会尝试排除它自己的成员,因为这些成员现在是 String.

的成员

我问的可能吗?我怀疑答案是,但我想我会问。

在发布这个问题前几秒钟,我想到了一个主意,而且它奏效了。与其排除 keyof stringOmit 所做的),不如让 CharArray 使用 string[K](如果存在)。

type CharArray = {
  [K in MethodNames<Array<string>>]: K extends keyof string ? string[K] : Array<string>[K];
};

现在,虽然引擎 可以 争论循环引用,但它只是将 string 的属性与其自身合并,所以它并不关心。 (至少,我认为是这个原因。)