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">"
我真的无法解释为什么,需要帮助!
如果这不能代表您尝试做的事情,那么这将没有多大帮助,但是在示例的函数中使用泛型是没有意义的。直接使用该类型,也许先为其别名:
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
}
在深入研究源代码一整天后,我想我得到了答案:
事实上,<T>
分别从T
和[T]
推断为'a'
和'b'
,这被称为候选类型。这两种候选类型具有不同的优先级:联合类型定义中的T
具有特殊的优先级值1
(查看 https://github.com/Microsoft/TypeScript/blob/master/src/compiler/types.ts,第 4398 行,NakedTypeVariable
枚举值),而[T]
具有公共优先级值0
,这意味着优先级顺序更高。
然后,在比较类型详细信息之前,较高优先级的值0
将立即覆盖1
。这就是类型'a'
被删除的原因。如果它们共享相同的优先级值,则它们将被合并(见下文)。
最简单的修复方法是删除<T extends 'a' | 'b'>
。 没有任何断言,[T]
中的T
将在解构虚拟表达式['b']
后推断为更广泛的类型string
。
我还发现了当存在多个候选类型时编译器是如何处理的:如果候选类型共享基本(如字符串、数字)协变类型,则使用联合符号|
连接它们。否则将得到最左边的类型,而右边没有类型是超类型。