简体   繁体   English

通用参数的联合类型

[英]Union type for generic param

The proxy return conditional randomly type.代理返回条件随机类型。

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

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 链接到游乐场

The right way to resolve this issue, any ideas?解决这个问题的正确方法,有什么想法吗?

This function:这个 function:

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

has a return type of:返回类型为:

number[] | string[]

This type says that the you either have an array of all numbers, or an array of all strings, but never a mix of both.这种类型表示您要么有一个所有数字的数组,要么有一个所有字符串的数组,但绝不是两者的混合。

So what is the type of the members of that type?那么该类型的成员的类型是什么? You might think it's number | string你可能认为它是number | string number | string , but that's not quite true. number | string ,但这并不完全正确。 If you take string | number如果你拿string | number string | number and add the array notation to the end, you get: string | number并将数组符号添加到末尾,您将获得:

(number | string)[]

This type says that it's an array of strings or numbers, and each member could be either.这种类型表示它是一个字符串或数字数组,每个成员都可以是。 You can now mix both.您现在可以将两者混合使用。 This is not the same thing.这不是一回事。 This means that the member type cannot be inferred, because that member type can't be used to construct the original array type.这意味着无法推断成员类型,因为该成员类型不能用于构造原始数组类型。

Now lets look at the generic function:现在让我们看看通用的 function:

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

This function tries to find the member type T for the array T[] .这个 function 试图找到数组T[]的成员类型T But as demonstrated above, there is no good member type for string[] | number[]但如上所示, string[] | number[]没有好的成员类型。 string[] | number[] . string[] | number[] So typescript fails to infer T and throws an error.所以 typescript 无法推断T并抛出错误。

So to make your function work, the member type T needs to be inferable.因此,要使您的 function 工作,成员类型T需要是可推断的。 You can do that by casting the return type of proxy to a compatible array type where only the members of the array are a union.您可以通过将代理的返回类型转换为兼容的数组类型来做到这一点,其中只有数组的成员是联合。

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

Now T can become string | number现在T可以变成string | number string | number and everything works like you expect. string | number和一切都像你期望的那样工作。

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

Playground 操场

The error happens because how the type argument T resolves for that call to func .发生错误是因为类型参数T如何解析对func的调用。 The return type of proxy is proxy的返回类型是

number[] | string[]

and the type for T gets inferred based on how number[] | string[]并根据number[] | string[]的方式推断T的类型number[] | string[] fits in the following signature: number[] | string[]符合以下签名:

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

So x must be an array of T s, which may be any type as far as func is concerned.所以x必须是T的数组,就func而言,它可以是任何类型。 In the case of number[] | string[]number[] | string[]的情况下number[] | string[] the type for T is inferred to be number , because number[] is the first type in the union that matches T[] for x . number[] | string[] T的类型被推断为number ,因为number[]是联合中第一个与xT[]匹配的类型。 Unfortunately, string[] is not taken into account.不幸的是,没有考虑到string[]

You might want T to be number | string您可能希望Tnumber | string number | string for this call, and you can do that by explicitly specifying the types while calling func :此调用的number | string ,您可以通过在调用func时显式指定类型来做到这一点:

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

The answer to the question this duplicates explains why TypeScript doesn't always infer unions for generic type parameters; 这个重复的问题的答案解释了为什么 TypeScript 并不总是推断泛型类型参数的联合; it's because it's often indicative of an error when callers specify multiple things for a single generic type parameter, and if the compiler always inferred a union in such situations, it would allow a lot of probably-wrong code.这是因为当调用者为单个泛型类型参数指定多个事物时,它通常表示错误,并且如果编译器总是在这种情况下推断出一个联合,它将允许很多可能错误的代码。 See microsoft/TypeScript#19656 for "official" discussion about this.有关此问题的“官方”讨论,请参见microsoft/TypeScript#19656

Anyway in your case I would probably change the func() signature to be like this:无论如何,在您的情况下,我可能会将func()签名更改为:

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

in which case T is actually the type of the array passed in and not of its members, which is T[number] .在这种情况下, T实际上是传入数组的类型,而不是其成员的类型,即T[number] That should work for you, I think.我想这应该对你有用。

Hope that helps;希望有帮助; good luck!祝你好运!

Playground link to code Playground 代码链接

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

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