打字稿不能用通用扩展字符串联合类型推断正确的类型? [英] Typescript doesn't infer correct type with Generic extending string union type?

查看:22
本文介绍了打字稿不能用通用扩展字符串联合类型推断正确的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

type Test = 'a' | 'b' | 'c';

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

像这样..我希望 arg 在 if 块中推断出 'a'.

like this.. I expect arg inferred 'a' in if block.

但 ts 只是推断为 T.

but ts infer as just T.

为什么会出现这种情况?

why this situation?

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

I think that extends keyword has something...

推荐答案

问题是你的类型 T 不是 Test 而是一个子集,我们可以说每个可以代替 T 使用的类型,每个 for union 表示具有相同或更少联合成员的类型.考虑扩展 Test 的示例类型:

The thing is that your type T is not Test but is a subset, we can say every type which can be used instead of T, and every for union means a type which has the same or less union members. Consider example type which extends Test:

type Test = 'a' | 'b' | 'c';
type SubTest = 'b' | 'c'

type IsSubTest = SubTest extends Test ? true : false // evaluates to true

正如你所看到的 SubTest 没有 a 成员,但它可以分配给 Test,因此我们可以使用 foo 具有这种类型的函数.

As you can see SubTest doesn't have a member but it is assignable to Test, therefore we can use foo function with such a type.

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

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

Everything good, no error. But that means that your condition arg === 'a' will never be met, as there is no member a in SubTest, that is why TS cannot assume that inside the condition we work with a, as in this situation this branch is totally not reachable and inside it will be type never. We can even write such function and check:

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

好的,但即使 TS 没有缩小到 a,因为条件很明确,任何通过它的东西都将是 a,毫无疑问!

Ok but even though why TS is not narrowing to a, as the condition is clear anything which will pass it will be a, no doubt here!

让我们尝试手动重现原始条件中存在的相同类型的守卫,条件检查左值 x(从 Test 扩展)是否等于右值 y(扩展 Test)

Lets try reproduce manually the same type guard which exists in the original condition, and the condition checks if the left value say x (which extends from Test), equals to the right value say y(which extends 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 === y 不适用于 XY

As you can see such typeguard cannot be even written. As X and Y can not overlap, therefor the condition x === y is not valid for all members of X and Y

总而言之,TS 不能将不能重叠的类型的条件考虑为类型保护,因此类型没有被缩小.

In summary TS cannot consider conditions on types which can not overlap as type guards, therefor type is not narrowed.

这篇关于打字稿不能用通用扩展字符串联合类型推断正确的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆