正如所写,
type OptionalArgBroken<Arg> = Arg extends undefined ?
() => void :
(arg: Arg) => void;
is a 分配条件类型因为正在检查的类型,Arg
,是一个裸泛型类型参数。
“分布式”意味着如果Arg
传入的是一个union,那么将分别评估联合体的每个成员的类型,然后重新组合在一起(因此操作是分散式整个联盟)。换句话说,OptionalArgBroken<A | B | C>
将与以下相同OptionalArgBroken<A> | OptionalArgBroken<B> | OptionalArgBroken<C>
.
这可能不是您的本意,您在签入时对结果感到满意就证明了这一点[]
(这使得检查类型不再通过“服装”来“裸体”)。
此外,TypeScript 编译器将boolean
类型作为并集的简写true
and false
, 所谓的布尔文字类型:
type Bool = true | false;
// type Bool = boolean
如果您将鼠标悬停在Bool
在带有 IntelliSense 的 IDE 中,您将看到Bool
上面显示为boolean
.
如果您想到这可能会感到惊讶boolean
作为单一类型而不是其他两种类型的联合。当你经过时就会出现这种情况boolean
分配条件类型:OptionalArgBroken<boolean>
is OptionalArgBroken<true | false>
这是OptionalArgBroken<true> | OptionalArgBroken<false>
这是
type OABBool = OptionalArgBroken<boolean>;
// type OABBool = ((arg: false) => void) | ((arg: true) => void)
您传入了您认为是单一类型的内容,并得到了函数类型的联合。哎呀。 (看微软/TypeScript#37279)
并且函数类型的联合只能通过路口他们的参数。阅读关于支持调用函数联合的 TS3.3 发行说明有关原因的信息。
但这意味着类型的值OptionalArgBroken<boolean>
只能使用类型参数来调用true & false
,减少为never
(see 微软/TypeScript#31838)因为不存在两者兼而有之的值true
and false
.
And 所以,当你尝试打电话时haveArgBroken
,它期望传入的参数类型为never
:
const haveArgBroken: OptionalArgBroken<boolean> = function (b: boolean) { };
// haveArgBroken(arg: never): void
And true
不属于类型never
,所以失败了:
haveArgBroken(true); // Type error
这就是为什么你的原始代码不起作用。
请注意,同样的事情也会发生
type ExtendsUndefined<T> = T extends undefined ? 'yes' : 'no'
但这是良性的,因为ExtendsUndefined<boolean>
变成ExtendsUndefined<true> | ExtendsUndefined<false>
这是'no' | 'no'
减少到只是'no'
。它恰好是你想要的,但只是因为没有办法区分'no'
那来自true
与来自的那个false
.
Playground 代码链接