打字稿没有用泛型扩展字符串联合类型推断正确的类型?


type Test = 'a' | 'b' | 'c';
function foo<T extends Test>(arg: T) {
if (arg === 'a') {
console.log(arg);
}
}

喜欢这个。。我希望 arg 推断出 if 块中的"a"。

但 ts 推断为只是 T。

为什么会出现这种情况?

我认为extends关键字有一些东西...

问题是你的类型T不是Test而是子集,我们可以说每个可以使用的类型代替T,每个 for union 意味着具有相同或更少工会成员的类型。考虑扩展Test的示例类型:

type Test = 'a' | 'b' | 'c';
type SubTest = 'b' | 'c'
type IsSubTest = SubTest extends Test ? true : false // evaluates to true

如您所见SubTest没有a成员,但它可以分配给Test,因此我们可以将foo函数与这样的类型一起使用。

const arg: SubTest = 'b'
foo(arg)

一切都很好,没有错误。但这意味着您的条件arg === 'a'永远不会得到满足,因为SubTest中没有成员a,这就是为什么 TS 不能假设在我们使用的条件内部a,因为在这种情况下,该分支是完全无法访问的,内部将是never型。我们甚至可以编写这样的函数并检查:

function foo(arg: SubTest) {
if (arg === 'a') { // compilation error, condition will be always false
console.log(arg);
}
}

好的,但即使为什么 TS 没有缩小到a,因为条件很清楚,任何通过它的东西都会a,毫无疑问!

让我们尝试手动重现原始条件下存在的相同类型保护,条件检查左侧值是否表示 x(从 Test 延伸(,等于右侧值表示 y(扩展 Test(

function isTestMember<X extends Test, Y extends Test>(x: X, y: Y): x is Y { 
return x == y  // error we cannot compare member of X with member of Y
}

如您所见,这种类型保护甚至无法编写。由于 X 和 Y 不能重叠,因此条件x === yXY的所有成员都无效

总之,TS不能考虑不能重叠的类型作为类型保护的条件,因此类型不缩小。

相关内容

最新更新