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">"
我真的无法解释为什么,需要帮助!
答案 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']
结合在一起。否则,将获得最左边的类型,而右边的任何类型都不是超级类型。