通用参数的联合类型

时间:2020-05-26 19:05:17

标签: typescript generics union

代理返回条件随机类型。

const numbersArray = [1,2,3,4];
const stringsArray = ['1','2','3','4'];


function func<T>(array: T[]): T[][] {
  return [[array[0], array[1]], [array[2], array[3]]];
}

const proxy = () => Math.random() < 0.5 ? numbersArray : stringsArray;

const resulNumbers = func(numbersArray);

const resultStrings = func(stringsArray);

const resultUnion = func(proxy()); // error

错误

const proxy: () => number[] | string[]

Argument of type 'number[] | string[]' is not assignable to parameter of type 'number[]'.
  Type 'string[]' is not assignable to type 'number[]'.
    Type 'string' is not assignable to type 'number'.(2345)

link to playground

解决这个问题的正确方法,有什么想法吗?

3 个答案:

答案 0 :(得分:1)

此功能:

const proxy = () => Math.random() < 0.5 ? numbersArray : stringsArray;

的返回类型为:

number[] | string[]

这种类型表示您要么拥有一个由所有数字组成的数组,要么具有一个由所有字符串组成的数组,但是永远不会将两者结合在一起。

那么该类型的成员的类型是什么?您可能会认为它是number | string,但这不是相当的事实。如果您使用string | number并将数组符号添加到末尾,则会得到:

(number | string)[]

此类型表示它是字符串或数字的数组,每个成员可以是。您现在可以将两者混合使用。这不是同一回事。这意味着无法推断成员类型,因为该成员类型不能用于构造原始数组类型。

现在让我们看一下泛型函数:

function func<T>(array: T[]): T[][] {
  return [[array[0], array[1]], [array[2], array[3]]];
}

此函数尝试查找数组T的成员类型T[]。但是如上所述,string[] | number[]没有好的成员类型。因此,打字稿无法推断T并抛出错误。

因此,要使您的函数正常工作,成员类型T必须是可推断的。您可以通过将代理的返回类型转换为仅数组成员为联合的兼容数组类型来实现。

const proxy: () => (string | number)[] =
  () => Math.random() < 0.5 ? numbersArray : stringsArray;

现在T可以成为string | number,一切正常。

const resultUnion = func(proxy()); // type: (string | number)[][]

Playground

答案 1 :(得分:0)

发生错误是因为类型参数T如何解决对func的调用。 proxy的返回类型为

number[] | string[]

,根据T符合以下签名的方式来推断number[] | string[]的类型:

function func<T>(x: T[]): T[][]

因此x必须是T的数组,就func而言,可以是任何类型。对于number[] | string[],推断T的类型为number,因为number[]是联合体中与{{ 1}}。不幸的是,T[]没有被考虑。

您可能希望x成为此调用的string[],并且可以通过在调用T时显式指定类型来实现:

number | string

答案 2 :(得分:0)

the question this duplicates的回答解释了为什么TypeScript并不总是推断通用类型参数的并集;这是因为当调用者为单个泛型类型参数指定多个内容时,它通常表示错误,并且如果编译器在这种情况下总是推断出并集,则将允许很多可能错误的代码。有关此问题的“正式”讨论,请参见microsoft/TypeScript#19656

无论如何,我可能会更改func()签名,如下所示:

function func<T extends any[]>(array: T): T[number][][] {
  return [[array[0], array[1]], [array[2], array[3]]];
}

在这种情况下,T实际上是传入数组而不是其成员的类型,即T[number]。我认为,这应该对您有用。

希望有所帮助;祝你好运!

Playground link to code