Javascript 获得一份;切片;字体脚本';参数';元组

Javascript 获得一份;切片;字体脚本';参数';元组,javascript,typescript,Javascript,Typescript,考虑参数实用程序类型,其底层类型是元组: 我有一个函数SomeFunction。为了将函数的参数用作类型,我编写了参数 现在让我们假设我想使用函数的参数作为类型,除了第一个参数 显然,对于数组,我会使用类似于…args.slice(1)。但我不知道有一个用于类型脚本定义的切片实用程序忽略仅适用于对象 提供一个RemoveFirstFromTuple实用程序。但这有点复杂。在类型定义中是否有提取元组一部分的内置方法?是的,您可以在函数类型上使用,方法非常类似于: 这是通过on实现的,因此比上面相对

考虑
参数
实用程序类型,其底层类型是元组:

我有一个函数
SomeFunction
。为了将函数的参数用作类型,我编写了
参数

现在让我们假设我想使用函数的参数作为类型,除了第一个参数

显然,对于数组,我会使用类似于
…args.slice(1)
。但我不知道有一个用于类型脚本定义的切片实用程序<代码>忽略仅适用于对象

提供一个
RemoveFirstFromTuple
实用程序。但这有点复杂。在类型定义中是否有提取元组一部分的内置方法?

是的,您可以在函数类型上使用,方法非常类似于:

这是通过on实现的,因此比上面相对简单的
参数sextfirst
实现计算量更大。如果您在长元组(长度超过25个左右)上尝试此操作,您可能会看到递归错误。如果您在行为不良的类型(如非定长元组或事物的并集)上尝试此方法,您可能会得到奇怪的结果。它很脆弱;小心点

让我们验证一下它是否有效:

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;
type Test = TupleSplit<readonly ["a", "b", "c", "d", "e"], 3>
// type Test = [readonly ["a", "b", "c"], readonly ["d", "e"]]
最后,
TupleSlice
生成从起始位置
S
到结束位置
E
的tuple
T
切片(切记,切片包括起始索引,不包括结束索引)通过获取
T
的第一个
E
元素并跳过结果的第一个
S
元素:

type TupleSlice<T extends readonly any[], S extends number, E extends number> =
    SkipFirst<TakeFirst<T, E>, S>
这看起来不错;从
slice()
返回的数组具有准确表示其值的类型

当然,有很多警告;如果为
S
E
将负数或非整数传递给
slice()
,则
TupleSlice
很可能与数组切片实际发生的情况不符:负的“从结尾”行为可能是可以实现的,但它会更加丑陋;非整数,甚至仅仅是
number
还没有被测试过,但我希望递归警告和其他东西会在晚上出现。小心

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]
type Test = TupleSplit<readonly ["a", "b", "c", "d", "e"], 3>
// type Test = [readonly ["a", "b", "c"], readonly ["d", "e"]]
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];
type TupleSlice<T extends readonly any[], S extends number, E extends number> =
    SkipFirst<TakeFirst<T, E>, S>
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); // [];