将类型推送到元组的末尾 [英] Push type to the end of the tuple

查看:22
本文介绍了将类型推送到元组的末尾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以在元组的开头添加元素,或者从那里删除它

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 Pushing 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆