如何解决在TypeScript中双展开嵌套的可变参数元组
tl; dr :我要强烈键入以下内容。
const foo = [ 'a' ] as const;
const bar = [ 1 ] as const;
const baz = [ true ] as const;
const concatted = foo.concat(bar,baz);
type Concatted = typeof concatted; // expect ['a',1,true]
我已经找到了如何为0..n参数添加定义的方法,但是我想对任意数量的参数进行添加,最好使用一个或两个定义。
假设我有
const strArray = [ 'a' ] as const;
const numArray = [ 1 ] as const;
const concatenated = strArray.concat(numArray);
我们知道,所连接的精确等于['a',1]
。我已经弄清楚了如何为concat()
编写类型定义,从而为我们提供了这一点。
declare global {
interface ReadonlyArray<T> {
concat<
A extends ReadonlyArray<T>,I extends ReadonlyArray<unknown>
>(this: A,items: C): [...A,...I];
}
}
type Concatenated = typeof concatenated; // => ['a',1]
但是,JavaScript的Array.concat()
接受任意数量的数组。所以现在开始吧
const strArray = [ 'a' ] as const;
const numArray = [ 1 ] as const;
const boolArray = [ true ] as const;
const concatenated = strArray.concat(numArray,boolArray); // => [ 'a',true ]
在TypeScript 4的variadic tuples之前,解决方案类似于
declare global {
interface ReadonlyArray<T> {
concat<
A extends ReadonlyArray<T>,items: I): [...A,...I];
concat<
A extends ReadonlyArray<T>,I1 extends ReadonlyArray<unknown>,I2 extends ReadonlyArray<unknown>
>(this: A,item1: I1,item2: I2): [...A,...I1,...I2];
// ...additional concat() definitions through I_n...
}
}
我希望有了TypeScript 4,我可以做些更简单的事情
declare global {
interface ReadonlyArray<T> {
concat<
A extends ReadonlyArray<T>,I extends ReadonlyArray<ReadonlyArray<unknown>>
>(this: A,...items: I): [...A,...(...I)];
}
}
这显然行不通。我想使用
((val: ReadonlyArray<ReadonlyArray<unknown>>) => void) extends ((val: [infer U,...infer R]) => void)
? [...U,...<something something recurse with R>]
: never
我从来没有掌握过的模式,也许与this answer中使用Extract<>
的魔术同时使用。
如果类型可以在没有任何魔术的情况下进行递归,那将非常好。然后我可以轻松地写:
type Concat<T extends ReadonlyArray<ReadonlyArray<unknown>>> =
T extends [ReadonlyArray<unknown>,...infer U]
? [...T[0],...Concat<U>]
: [];
interface ReadonlyArray<T> {
concat<
A extends ReadonlyArray<T>,I extends ReadonlyArray<ReadonlyArray<unknown>>
>(this: A,...Concat<I>];
}
顺便说一句,我从来不明白为什么不支持递归类型(只要它们在n个深度之内解析)。无限递归当然是不好的/不可能的,但是我认为很容易/有效地支持大小为100或小于100的元组的这种语法。
解决方法
recursive conditional types的官方支持将在Typescript 4.1中添加
有了它,我们将能够:
type Concat<T> =
T extends [infer Head,...infer Tail]
? Head extends ReadonlyArray<unknown>
? [...Concat<Head>,...Concat<Tail>] : [Head,...Concat<Tail>]
: T
上面的定义允许传递数组和/或值以连接成一个新数组(就像常规的concat一样)
递归限制为50个嵌套类型的实例
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。