gpt4 book ai didi

javascript - 获取 Typescript "slice"元组的 'Parameters'

转载 作者:行者123 更新时间:2023-12-04 07:38:44 25 4
gpt4 key购买 nike

考虑 Parameters实用程序类型,其底层类型为元组:https://www.typescriptlang.org/docs/handbook/utility-types.html#parameterstype
我有一个函数SomeFunction .要将函数的参数用作类型,我写 Parameters<SomeFunction> .
现在假设我想将函数的参数用作除第一个参数之外的类型。
显然,对于一个数组,我会使用类似 ...args.slice(1) .但我不知道 Typescript 定义的切片实用程序。 Omit仅适用于对象。
An answer to this SO question提供RemoveFirstFromTuple效用。但这有点令人费解。是否有在类型定义中提取部分元组的内置方法?

最佳答案

是的,您可以使用 conditional type inference关于函数类型,与 the Parameters utility type 的方式非常相似is implemented :

type ParametersExceptFirst<F> = 
F extends (arg0: any, ...rest: infer R) => any ? R : never;
相比于
// from lib.es5.d.ts
type Parameters<T extends (...args: any) => any> =
T extends (...args: infer P) => any ? P : never;
并验证它是否有效:
declare function foo(x: string, y: number, z: boolean): Date;
type FooParamsExceptFirst = ParametersExceptFirst<typeof foo>;
// type FooParamsExceptFirst = [y: number, z: boolean]
declare function foo(x: string, y: number, z: boolean): Date;
Playground link to code

更新:使用数字文字对元组进行任意切片是可能的,但不是很漂亮并且有一些警告。首先让我们写 TupleSplit<T, N>它需要一个元组 T和一个数字 literal类型 N , 并拆分元组 T在索引 N ,返回两 block :第一 block 是第一个 N T 的元素,第二件就是在那之后的一切。 (如果 N 大于 T 的长度,则第一段是 T 的全部,第二段为空):
type TupleSplit<T, N extends number, O extends readonly any[] = readonly []> =
O['length'] extends N ? [O, T] : T extends readonly [infer F, ...infer R] ?
TupleSplit<readonly [...R], N, readonly [...O, F]> : [O, T]
这通过 recursive conditional types 工作在 variadic tuples因此比相对简单的 ParametersExceptFirst 计算量更大上面的实现。如果您在长元组(长度超过 25 个左右)上尝试此操作,您可能会看到递归错误。如果你在行为不端的类型上尝试这个,比如非固定长度的元组或事物的联合,你可能会得到奇怪的结果。很脆弱;小心它。
让我们验证它是否有效:
type Test = TupleSplit<readonly ["a", "b", "c", "d", "e"], 3>
// type Test = [readonly ["a", "b", "c"], readonly ["d", "e"]]
看起来不错。

现在我们可以使用 TupleSplit<T, N>实现 TakeFirst<T, N> , 只返回第一个 N T 的元素, 和 SkipFirst<T, N> ,跳过第一个 N T 的元素:
type TakeFirst<T extends readonly any[], N extends number> =
TupleSplit<T, N>[0];

type SkipFirst<T extends readonly any[], N extends number> =
TupleSplit<T, N>[1];
最后 TupleSlice<T, S, E>生成元组切片 T从起始位置 S到结束位置 E (记住,切片包括起始索引,不包括结束索引)取第一个 E T 的元素并跳过第一个 S结果的要素:
type TupleSlice<T extends readonly any[], S extends number, E extends number> =
SkipFirst<TakeFirst<T, E>, S>

为了证明这或多或少代表什么数组 slice()确实,让我们编写一个函数并对其进行测试:
function slice<T extends readonly any[], S extends number, E extends number>(
arr: readonly [...T], start: S, end: E
) {
return arr.slice(start, end) as readonly any[] as TupleSlice<T, S, E>;
}

const tuple = ["a", "b", "c", "d", "e"] as const
// const tuple: readonly ["a", "b", "c", "d", "e"]

const ret0 = slice(tuple, 2, 4);
// const ret0: readonly ["c", "d"]
console.log(ret0); // ["c", "d"]

const ret1 = slice(tuple, 0, 9);
// const ret1: readonly ["a", "b", "c", "d", "e"]
console.log(ret1); // ["a", "b", "c", "d", "e"];

const ret2 = slice(tuple, 5, 3);
// const ret2: readonly []
console.log(ret2); // [];
这看起来不错;从 slice() 返回的数组具有准确表示其值的类型。
当然,有很多警告;如果您将负数或非整数传递给 slice()对于 SE ,然后 TupleSlice<T, S, E>很可能与数组切片实际发生的情况不对应:负面的“从头开始”行为可能是可以实现的,但它会更丑陋;非整数,甚至只是 number尚未经过测试,但我预计会在夜间出现递归警告和其他问题。被警告!
Playground link to code

关于javascript - 获取 Typescript "slice"元组的 'Parameters',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67605122/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com