给出以下类型定义和函数实现:
interface WithNumber {
foo: number;
}
interface WithString {
bar: string;
}
type MyType = WithNumber | WithString;
interface Parameter<C extends MyType = MyType> {
container: C
}
function isParameterWithNumberContainer(arg: Parameter): arg is Parameter<WithNumber> {
return typeof (arg.container as WithNumber).foo === "number";
}
function test(arg: Parameter<WithNumber | WithString>) {
if (isParameterWithNumberContainer(arg)) {
arg.container.foo;
return;
}
/*
* Error:
* Property 'bar' does not exist on type 'MyType'.
* Property 'bar' does not exist on type 'WithNumber'.
*/
arg.container.bar;
}
为什么Typescript没有缩小if-block下方arg
的类型,以防御类型后卫?在我看来,arg不可能是Parameter<WithString>
之外的东西。然而,Typescript仍然认为它是Parameter<WithNumber | WithString>
,因此在尝试访问arg.container.bar
时会出错。
答案 0 :(得分:3)
我试图找到适当的文件,但我不能。我对类型保护与if
语句一起使用的方式的理解是,then
分支上的类型被排除在else
分支上的联合类型之外。它没有深入探讨可以排除的类型。您的参数是一个泛型类型,其联合类型作为通用参数,因此else
分支上不会排除任何内容。
一个简单的解决方法是使参数成为联合类型:
function isParameterWithNumberContainer(arg: Parameter): arg is Parameter<WithNumber> {
return typeof (arg.container as WithNumber).foo === "number";
}
function test(arg: Parameter<WithNumber> | Parameter<WithString>) {
if (isParameterWithNumberContainer(arg)) {
arg.container.foo;
return;
}
arg.container.bar;
}