联合泛型中的Typescript类型推断问题

时间:2019-03-08 13:00:11

标签: typescript

type SingleOrArray<T> = T | [T]

function f<T extends 'a' | 'b'>(a: SingleOrArray<T>, b: SingleOrArray<T>) {
    return a && b
}

f('a', ['b'])

然后我弄错了:Argument of type '"a"' is not assignable to parameter of type 'SingleOrArray<"b">',并且推断'f'是:

function f<"b">(a: SingleOrArray<"b">, b: SingleOrArray<"b">): SingleOrArray<"b">"

我真的无法解释为什么,需要帮助!

2 个答案:

答案 0 :(得分:1)

如果这不能代表您尝试执行的操作,那么这将无济于事,但是在示例函数中使用泛型毫无意义。只需直接使用类型,也许先使用别名即可:

type AOrB = 'a' | 'b';
function f(a: SingleOrArray<AOrB>, b: SingleOrArray<AOrB>) {
    return a && b
}

这样,类型将在两个参数中都是独立的。您可以在示例中解决此问题,方法是引入另一个类型参数,然后将第一个参数用作第二个参数。

function f<
    T1 extends 'a' | 'b',
    T2 extends 'a' | 'b'
>(a: SingleOrArray<T1>, b: SingleOrArray<T2>) {
    return a && b
}

答案 1 :(得分:0)

在研究了整整一天的源代码之后,我想我得到了答案:

实际上,<T>是分别从'a''b'推断为T[T]的,它们被称为候选类型。这两种候选类型具有不同的优先级:联合类型定义中的T具有特殊的优先级值1(查看https://github.com/Microsoft/TypeScript/blob/master/src/compiler/types.ts,第4398行,NakedTypeVariable枚举值),而{ {1}}具有共同的优先级值[T],这意味着优先级较高。

然后,在比较类型详细信息之前,较高优先级的值0将立即覆盖0。这就是删除类型1的原因。如果它们共享相同的优先级值,那么它们将被合并(见下文)。

最简单的解决方法是删除'a'。在没有任何断言的情况下,<T extends 'a' | 'b'>中的T在解构虚拟表达式[T]之后将被推断为更广泛的类型string

我还发现存在多个候选类型时编译器如何处理:如果候选类型共享基本(如字符串,数字)协变类型,则将它们与联合符号['b']结合在一起。否则,将获得最左边的类型,而右边的任何类型都不是超级类型。