繁体   English   中英

通用参数的联合类型

[英]Union type for generic param

代理返回条件随机类型。

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)

链接到游乐场

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

这个 function:

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

返回类型为:

number[] | string[]

这种类型表示您要么有一个所有数字的数组,要么有一个所有字符串的数组,但绝不是两者的混合。

那么该类型的成员的类型是什么? 你可能认为它是number | string number | string ,但这并不完全正确。 如果你拿string | number string | number并将数组符号添加到末尾,您将获得:

(number | string)[]

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

现在让我们看看通用的 function:

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

这个 function 试图找到数组T[]的成员类型T 但如上所示, string[] | number[]没有好的成员类型。 string[] | number[] 所以 typescript 无法推断T并抛出错误。

因此,要使您的 function 工作,成员类型T需要是可推断的。 您可以通过将代理的返回类型转换为兼容的数组类型来做到这一点,其中只有数组的成员是联合。

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

现在T可以变成string | number string | number和一切都像你期望的那样工作。

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

操场

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

number[] | string[]

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

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

所以x必须是T的数组,就func而言,它可以是任何类型。 number[] | string[]的情况下 number[] | string[] T的类型被推断为number ,因为number[]是联合中第一个与xT[]匹配的类型。 不幸的是,没有考虑到string[]

您可能希望Tnumber | string 此调用的number | string ,您可以通过在调用func时显式指定类型来做到这一点:

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

这个重复的问题的答案解释了为什么 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 代码链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM