这是因为innerType 是distributive conditional type 而innerType2 不是。
这意味着他们的行为不同。
引用distributive conditional types docs:
如果我们将联合类型插入 ToArray,则条件类型将应用于该联合的每个成员。
ToArray 等价于extractGeneric
因此,extractGeneric 首先尝试从 error 获取泛型参数,然后从 success 获取。因为error 没有通用参数,所以它返回unknown。这是设计使然
考虑这个伪代码:
type extractGeneric<Type> = Type extends error (unknown) | Type extends success<infer X> ? X | unknown : never
事实上,我们最终得到了X | unknown。因为unknown 的具体程度低于X 的联合X | unknown 返回unknown。
如何一般性地提取类型?
只需使用需要泛型参数的联合部分
type error = {
tag: 'error',
error: string
}
type success<T> = {
tag: 'success',
value: T
}
type Either<T> = error | success<T>;
type extractGeneric<Type> = Type extends success<infer X> ? X : never
type innerType = extractGeneric<Either<number>>; // number
您可能已经注意到它不会抛出错误,因为 Either extends success
或
你可以关闭分配:
type error = {
tag: 'error',
error: string
}
type success<T> = {
tag: 'success',
value: T
}
type Either<T> = error | success<T>;
type extractGeneric<Type> = [Type] extends [Either<infer X>] ? X : never
type innerType = extractGeneric<Either<number>>; // number
附:按照惯例,所有类型别名都应该大写。
// bad
type foo = number
// good
type Foo = number