在Typescript中,为数组定义一个类型,其中第一个元素比其余元素更具体

时间:2017-06-07 01:30:54

标签: typescript types

我想为第一个元素是特定类型(例如Function)的数组定义一个类型,其余元素是空类型。例如:

type FAs = [Function, {}, {}, {}, ...]; // pseudo code

这样的事情可能吗?

目的是提供这样的单参数函数:

const myCaller = ([fun, ...args]: FAs) => fun.apply(args);

另一种方法是使用myCaller的两个参数,如下所示:

const myCaller = (fun: Function, args: any[]) => fun.apply(args);

但出于审美原因,我宁愿使用单一论点。我也想知道类型系统是否支持可以说是任意长度的元组。也许出于我不理解的计算机科学原因,这样的事情是不可取的。

5 个答案:

答案 0 :(得分:11)

如果你定义

type FAs = [Function, {}];

然后,类型FAs的值将需要类型为Function的第一个元素,类型为{}的第二个元素,以及Function | {}的后续元素。这就是TypeScript文字数组类型的工作方式。来自TS docs

  

当访问已知索引集之外的元素时,将使用联合类型:

这应该做你想要的一切除了,因为你可以传递一个Function类型的值作为数组的第三个元素等。但实际情况确实如此,因为Function{}兼容。

没有办法解决这个问题。 TS中没有办法定义一个数组类型,其中第一个 n 元素属于某些特定类型,并且存在任意数量的其他特定类型的剩余元素。

  

我也想知道类型系统是否支持可以说是任意长度的元组。

实际上,类型系统支持任意长度的元组。如果你说

type Tuple = [number, number];

此类型与任何长度为2的或更高的数组兼容,其中包含数字。如果你说

type Tuple = [string, number];

此类型与任何长度为或更长的数组兼容,其中第一个元素为字符串,第二个为数字,第三个为字符串或数字等。我不会把这种行为的原因称为“基于计算机科学”;这更多的是TS检查的可行性。

另一种方法

interface Arglist {
  [index: number]: object;
  0: Function;
}

const a1: Arglist = [func];
const a2: Arglist = [22];                  // fails
const a3: Arglist = [func, "foo"];         // fails
const a4: Arglist = [func, obj];
const a5: Arglist = [func, obj, obj];

答案 1 :(得分:4)

在当前版本的Typescript中,可以使用数组扩展来实现:

type FAs = [Function, ...Array<{}>]

它支持1到n之间的任何长度(必填第一个元素)。

答案 2 :(得分:0)

我很确定这是你可以做的最好的打字稿2.3。你可以在lodash中看到这样的类型。

{{1}}

答案 3 :(得分:0)

我还想知道类型系统是否支持可以说是任意长度的元组。

从TS 4.0开始,您可以使用variadic tuple types。 例如,以类型安全的方式声明[func, ...<proper func args>]

type FAs<A extends unknown[], R> = [(...args: A) => R, ...A]

const myCaller = <A extends unknown[], R>([fn, ...args]: FAs<A, R>) =>
    fn.apply(null, args)
例:
const fn1 = (a1: string, a2: number) => true

const r1 = myCaller([fn1, "foo", 42]) // OK, r1 has type `boolean`
const r2 = myCaller([fn1, "foo", "bar"]) // error, `bar` has wrong type
const r3 = myCaller([fn1, "foo"]) // error, not enough arguments

Playground

答案 4 :(得分:0)

type First<T> = T extends [infer U, ...any[]] ? U : any;
type F = First<[number, boolean, string]> // number