是否可以在TypeScript中使用以下签名实现一个从现有类型中删除/排除基本类型的过滤器函数(通过正确的类型重新转换)?-
type basicType = 'string' | 'number' | 'boolean' | 'bigint';
function removeByType<T>(input: T[], ...types: basicType[]): Exclude<T, ?>[] {
// actual data filtering (irrelevant for this question)
}
我不担心确切的签名,只要它可以像这样使用(或类似):
const input = [1, 2, 3, 'four', false]; //=> Array<number | string | boolean>
const res = removeByType(input, 'string', 'boolean'); //=> Array<number>
如果这是不可能的,那么什么是下一个最好的事情呢?
到目前为止,我只能通过以下重新声明使它只适用于单值参数:
function removeByType<T>(input: T[], t: 'string'): Exclude<T, string>[];
function removeByType<T>(input: T[], t: 'number'): Exclude<T, number>[];
function removeByType<T>(input: T[], t: 'boolean'): Exclude<T, boolean>[];
function removeByType<T>(input: T[], t: 'bigint'): Exclude<T, bigint>[];
我正在努力弄清楚如何让它工作的名单,或者如果它是在所有可能的...
- 更新**
最终的解决方案是here,因为它是为iter-ops库的自定义操作符设计的。非常感谢Jared Smith的回答!
2条答案
按热度按时间xdyibdwo1#
这个问题的问题是类型没有术语级别的表示(例如,运行时
typeof
操作符给出的值只是字符串),而且你不能像Haskell类型类元编程那样从类型-〉术语开始,如果我们稍微调整一下签名,在类型级别实现这一点并不难。在术语级别实现它涉及到......?所以实现逻辑不一定是无关紧要的。我在下面用一个map实现了它,用实际类型和自由强制转换来Map原语的字符串类型。也许其他人会想出一个更聪明的解决方案来保护更多的类型安全。
Playground
最后一点提醒:我通常称这样的代码为“聪明”,但这并不一定是赞美。仔细权衡在代码库中包含这样的代码的利弊,以及你是否得到了足够的安全性来权衡复杂性。类型系统的诡计总是有趣的,但只是偶尔值得为生产代码IMO。
cl25kdpy2#
下面是我在玩它的时候自己创造的半答案:
它工作正常,但它的问题-值没有强制执行,也就是说,你可以传入任何像
bla-bla
字符串,TS不会抱怨。这就是为什么Jared Smith的早期解决方案更好的原因。除非,这个解决方案可以很容易地修复,以某种方式?