内含任何通用数组

时间:2018-09-22 13:27:05

标签: typescript generics

我想将类型声明为包含可传递给此构造函数的构造函数和参数的对数组。还有关于剩余函数参数的相同问题。我该怎么办?

例如在following code中,我希望带有{ type: A, config: "" }的行是错误的,因为A不接受string作为构造函数参数:

interface ISmth<T> {
  value: T;
}

interface ISmthConstructor<T> {
  new(value: T);
}

class A implements ISmth<number> {
  constructor(public value: number) {}
}

class B implements ISmth<string> {
  constructor(public value: string) {}
}

interface ISmthConfig<T> {
  type: ISmthConstructor<T>;
  config: T;
}; 

function f<T extends any[]>(...args: T) { // What should I use instead of `any`?
  return args;                            // It should array of ISmthConfig<U> with any `U`
}

var x = f(
  { type: A, config: 12 },
  { type: B, config: "" },
  { type: A, config: "" }, // I want this argument to be an error
)

var y: ISmthConfig<any>[] = [ // What should I use instead of `any`?
  { type: A, config: 12 },
  { type: B, config: "" },
  { type: A, config: "" }, // I want this line to be an error
];

1 个答案:

答案 0 :(得分:2)

首先:我将您对ISmthConstructor<T>的定义更改为以下内容:

interface ISmthConstructor<T> {
  new(value: T): ISmth<T>; // added return type
}

您代码中的版本隐式返回any类型,我想这很好,但似乎并不是您的意图。


今天构建的TypeScript(3.1.0-dev.20180922)使我希望正确的答案是告诉您等到TypeScript 3.1 comes out sometime this month (Sep 2018)然后执行此操作:

declare function f<T extends any[]>(
  ...args: { [K in keyof T]: ISmthConfig<T[K]> }
): void;

// no error, T inferred as [number, string]
f(
  { type: A, config: 12 }, 
  { type: B, config: "" }
);

// error, T inferred as [number, string, string | number]
f(
  { type: A, config: 12 }, 
  { type: B, config: "" },
  { type: A, config: "" } // error on type: string is not assignable to number
);

这将利用即将推出的mapped tuplesinference from mapped types功能。基本上,您是说位置K处的参数必须为ISmthConfig<T[K]>。如果编译器可以推断满足此条件的元组/数组类型T,则编译成功。否则,它将报告违规参数上的错误。

无论如何,这真的很有希望!


如果您需要在TypeScript 3.0上工作的东西,那么您最好要做的就是选择一些合理的最大长度的参数列表,并创建一个可以容纳该参数的函数:

function goodEnough<A0, A1, A2, A3, A4, A5, A6>(
  ...args: [ISmthConfig<A0>?, ISmthConfig<A1>?, ISmthConfig<A2>?, ISmthConfig<A3>?,
    ISmthConfig<A4>?, ISmthConfig<A5>?, ISmthConfig<A6>?]
) {
  return args;
}
goodEnough({ type: A, config: 12 }); // okay
goodEnough({ type: B, config: "" }); // okay
goodEnough(
  { type: A, config: 12 },
  { type: B, config: "" },
  { type: A, config: "" } // error, string not assignable to number
); 

它的缺点是具有任意限制和冗长,但至少可以起作用。

如果以上签名最终为您提供了args的不可用类型,其中包含许多可选的元组元素,或者您需要在TypeScript 2.9及以下版本中可用的功能,则可以执行一系列{{3} },甚至更为冗长:

function ugh<A0>(a0: ISmthConfig<A0>): [typeof a0];
function ugh<A0, A1>(
  a0: ISmthConfig<A0>, a1: ISmthConfig<A1>
): [typeof a0, typeof a1];
function ugh<A0, A1, A2>(
  a0: ISmthConfig<A0>, a1: ISmthConfig<A1>, a2: ISmthConfig<A2>
): [typeof a0, typeof a1, typeof a2];
function ugh(...args: ISmthConfig<any>[]): ISmthConfig<any>[] {
  return args;
}

ugh({ type: A, config: 12 }); // okay
ugh({ type: B, config: "" }); // okay
ugh(
  { type: A, config: 12 },
  { type: B, config: "" },
  { type: A, config: "" } // error, string not assignable to number
); 

那是功能,但是,嗯。


回顾一下:TypeScript 3.1可以很好地解决这个问题。请等待(或立即使用)。否则,会有各种厌恶情绪的回退/解决方法。

希望有帮助。祝你好运!