将类型推送到元组的末尾 [英] Push type to the end of the tuple
问题描述
我可以在元组的开头添加元素,或者从那里删除它
I can add element to the begining of the tuple, or remove it from there
type ShiftTuple<T extends any[]> = ((...t: T) => void) extends ((x: infer X, ...r: infer R) => void) ? R : never;
type UnshiftTuple<X, T extends any[]> = ((x: X, ...t: T) => void) extends ((...r: infer R) => void) ? R : never;
但是我很难用最后一个元素而不是第一个元素做同样的事情.
But I have difficulties with doing the same things with the last element instead of the first.
即使我写了函数
function f<X, Z extends any[]>(x: X, ...args: Z) {
return [...args, x]
}
打字稿说 它返回 any[]
.
有没有办法像(不支持)一样将新类型推入元组的末尾
Is there a way to push new type into the end of the tuple like (insupported)
export type PushTuple<T extends any[], X> = [...T, X];
推荐答案
更新 TS4.0+
TypeScript 4.0 引入了可变元组类型,支持Push以更直接的方式编码到元组的末尾......就像这样:
TypeScript 4.0 introduced variadic tuple types, which supports Push
ing to the end of a tuple in a much more straightforward way... like this:
type Push<T extends readonly any[], V> = [...T, V];
TS3.9-的旧答案:
OLD ANSWER FOR TS3.9-:
我通常根据您所称的 Unshift
来定义 Push
(但我称之为 Cons
),像这样:
I usually define Push
in terms of what you're calling Unshift
(but which I call Cons
), like this:
type Cons<H, T extends readonly any[]> =
((head: H, ...tail: T) => void) extends ((...cons: infer R) => void) ? R : never;
type Push<T extends readonly any[], V>
= T extends any ? Cons<void, T> extends infer U ?
{ [K in keyof U]: K extends keyof T ? T[K] : V } : never : never;
Push<T, V>
的工作方式是使元组比 T
长一个元素(它使用 Cons
来实现)然后它 映射它.它用 T
中的相应元素填充输出的初始元素,然后剩下的任何东西都填充到 V
.长度为 n+1 的映射元组中唯一不是长度为 n 的元组的索引的元素索引是索引 n 本身,这意味着新元组的最后一个元素是V
.(我确保 分发 在 T
上,以防它是一个联合.)
The way Push<T, V>
works is to make a tuple one element longer than T
(which it does with Cons
) and then it maps over it. It fills the initial elements of the output with the corresponding elements from T
, and then anything left over it fills in V
. The only element index in a mapped tuple of length n+1 that is not an index of a tuple of length n is the index n itself, so that means the last element of the new tuple is V
. (I made sure to distribute over T
in case it's a union.)
请注意,这仅适用于非边缘情况...不要指望 readonly
, 可选和 rest 元组元素或非元组数组表现良好;如果你想定义它,你必须自己解决这些限制.
Note that this only works for non-edge cases... don't expect readonly
, optional, and rest tuple elements or non-tuple arrays to behave well; you'd have to work around those restrictions yourself if you want to define it.
恢复常规答案:
那么你可以像这样定义f()
:
So then you can define f()
like this:
function f<X, Z extends any[]>(x: X, ...args: Z): Push<Z, X>;
function f(x: any, ...args: any[]): any[] {
return [...args, x]
}
(请注意,我使用 overload 将自己从担心编译器试图理解实现符合 Push<Z, X>
:
(note that I use an overload to free myself from worrying about the compiler trying and failing to understand that the implementation complies with Push<Z, X>
:
它可以按您的预期工作:
And it works as you expect:
const s = f(4, "hey", false);
// const s: [string, boolean, number]
console.log(s); // ["hey", false, 4]
好的,希望对您有所帮助;祝你好运!
Okay, hope that helps; good luck!
这篇关于将类型推送到元组的末尾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!