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

发布于 2025-01-10 00:47:09 字数 2143 浏览 1 评论 0原文

对于我的 iPhone 上的一些 hacky 脚本(不是我为生产编写的代码),我经常发现自己将 string 视为 string[] (字符数组)。由于在手机上打字比在键盘上打字慢得多,并且考虑到 57 个字符宽的屏幕尺寸,字符非常宝贵,因此我编写了一些代码,采用 Array.prototype 的每个方法,将其映射到 Array.from(this)[fn],并将其附加到 String.prototype 如果它尚不存在。例如,我希望 .slice() 仍然返回 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']。万岁。

现在,我想编写更新的接口字符串,而无需手动复制Array中的每个有效声明。 (有时 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 {};

<一href="https://www.typescriptlang.org/play?#code/C4TwDgpgBAshwAsD2ATAcgQwLYQM4B4AVAPigF4oBvAKCi gG0BpKASwDsoBrCEJAMyiEoAMii5gAJ3YBzALoAuQU1lQIAD2AQ2KXFAAUAOiMYJ03IoxsQ9WQEpypSyCgB+KM0VsIANwg SA3NQAvvTcvAJCouJSbHKB1KCQsPDIOgDyfESkFDR0TKwccIiomDgEJApKjLKBQfGJ0ADCCCYAghISGM4UaVgswPhFqbgZ +O2dIPjRMsTEADRcPPxikjPxKBAAxg​​A2JtDS20gARhjbVLQFmhJ8GJvQAMqrsaoaWjpQzW0dXVRBwdTUdRgJASYC-fxAA" rel="nofollow noreferrer">TS Playground

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

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

For some hacky scripting on my iPhone (not code I would ever write for production), I frequently find myself treating strings as string[] (a character array). Since typing on a phone is significantly slower than on a keyboard and characters are at a premium given the 57-character-wide screen size, I wrote some code that takes every method of Array.prototype, maps it to Array.from(this)[fn], and attaches it to String.prototype if it does not already exist. For example, I want .slice() still to return a string, not a 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)
    }
  )

Now I can run 'abc'.filter(x => x !== 'b') and receive ['a', 'c']. Huzzah.

Now I want to write the updated interface String without manually copying over every valid declaration from Array<T>. (Sometimes play.js will read a .d.ts file.)

My best attempt introduces circular type references, which doesn't surprise me.

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

Up until I make String extend CharArray, everything works fine. CharArray has the proper methods. Once I add the extension, CharArray tries to exclude its own members, since those members are now members of String.

Is what I'm asking even possible? I suspect the answer is no, but I thought I would ask.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小姐丶请自重 2025-01-17 00:47:09

就在发布这个问题之前几秒钟,我突然想到了一个想法,而且它确实有效。不要排除 keyof string (这是 Omit 所做的),而是让 CharArray 使用 string[K] 如果存在。

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

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

Mere seconds before posting this question, an idea occurred to me, and it works. Rather than excluding keyof string (which is what Omit does), make CharArray use string[K] if it exists.

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

Now, while the engine could argue a circular reference, it's only merging the properties of string with themselves, so it doesn't care. (At least, I think that's the reason.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文