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

ant*_*sis 19 types typescript

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

type FAs = [Function, {}, {}, {}, ...]; // pseudo code
Run Code Online (Sandbox Code Playgroud)

这样的事情可能吗?

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

const myCaller = ([fun, ...args]: FAs) => fun.apply(args);
Run Code Online (Sandbox Code Playgroud)

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

const myCaller = (fun: Function, args: any[]) => fun.apply(args);
Run Code Online (Sandbox Code Playgroud)

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

小智 17

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

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

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


小智 16

如果你定义

type FAs = [Function, {}];
Run Code Online (Sandbox Code Playgroud)

那么类型的值FAs将需要第一个类型元素Function,第二个元素元素{}和后续元素Function | {}.这就是TypeScript文字数组类型的工作方式.来自TS文档:

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

这应该做你想要的一切,除了你能够传入一个Function-typed值作为数组的第三个元素等.但事实上,无论如何Function都是如此,因为兼容{}.

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

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

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

type Tuple = [number, number];
Run Code Online (Sandbox Code Playgroud)

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

type Tuple = [string, number];
Run Code Online (Sandbox Code Playgroud)

这种类型与长度为2 或更长的任何数组兼容,它有一个字符串作为它的第一个元素,一个数字作为它的第二个,并且字符串或数字作为它的第三个等等.我不会称这种行为的原因"以计算机科学为基础; 更重要的是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];
Run Code Online (Sandbox Code Playgroud)

  • 看起来这个答案现在已经过时了?有[较新](/sf/ask/3108146751/# 53119931)回答这个问题,[包括 TypeScript 4.0](/sf/ask/3108146751/ -更具体/62634698#62634698)。 (3认同)

小智 6

假设您想要一个Array至少有两个元素的元素,第一个元素是 type A,后面的所有元素都是 type B。更通用的方法是定义交叉点类型,如下所示:

type A = string
type B = number

// ensures that there are at least two elements
interface Foo {
  0: A;
  1: B;
}

// ensures that the first element is of type A and any after that of type B
type Bar = [A, ...B[]]

type MyArrayType = Foo & Bar

let a: MyArrayType

a = ['hello world', 1] // works
a = ['hello world', 1, 2] // works
a = ['hello world'] // fails
a = ['hello', 'world'] // fails
Run Code Online (Sandbox Code Playgroud)

请注意,即使 A 不是 B 的子集,这也是有效的。这是接受的答案起作用所必需的。

我意识到原来的问题不需要这个约束。但由于我遇到了这条带有这些限制的线程,它可能会对其他人有所帮助。