使打字稿接口扩展另一个接口,不包括已经定义的键
对于我的 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 +O2dIPjRMsTEADRcPPxikjPxKBAAxgA2JtDS20gARhjbVLQFmhJ8GJvQAMqrsaoaWjpQzW0dXVRBwdTUdRgJASYC-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 string
s 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 {};
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
就在发布这个问题之前几秒钟,我突然想到了一个想法,而且它确实有效。不要排除
keyof string
(这是Omit
所做的),而是让CharArray
使用string[K]
如果存在。现在,虽然引擎可以争论循环引用,但它只是将
string
的属性与其自身合并,所以它并不关心。 (至少,我认为这就是原因。)Mere seconds before posting this question, an idea occurred to me, and it works. Rather than excluding
keyof string
(which is whatOmit
does), makeCharArray
usestring[K]
if it exists.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.)