Typescript不';无法使用泛型扩展字符串联合类型推断正确的类型? type Test='a'|'b'|'c'; 函数foo(arg:T){ 如果(arg=='a'){ 控制台日志(arg); } }

Typescript不';无法使用泛型扩展字符串联合类型推断正确的类型? type Test='a'|'b'|'c'; 函数foo(arg:T){ 如果(arg=='a'){ 控制台日志(arg); } },typescript,typescript-typings,Typescript,Typescript Typings,像这样。。我希望在if块中使用arg推断的“a” 但是ts推断为T 为什么会出现这种情况 我认为extends关键字有点 问题是,您的类型T不是Test,而是一个子集,我们可以说每个类型都可以用来代替T,而每个for联合都意味着一个具有相同或更少联合成员的类型。考虑扩展代码< >代码>测试>代码>: type Test = 'a' | 'b' | 'c'; function foo<T extends Test>(arg: T) { if (arg === 'a') {

像这样。。我希望在if块中使用arg推断的“a”

但是ts推断为T

为什么会出现这种情况


我认为
extends
关键字有点

问题是,您的类型
T
不是
Test
,而是一个子集,我们可以说每个类型都可以用来代替
T
,而每个for联合都意味着一个具有相同或更少联合成员的类型。考虑扩展代码< >代码>测试>代码>:

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

function foo<T extends Test>(arg: T) {
  if (arg === 'a') {
    console.log(arg);
  }
}
正如您所看到的,
SubTest
没有
a
成员,但它可分配给
Test
,因此我们可以对这种类型使用
foo
函数

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

type IsSubTest = SubTest extends Test ? true : false // evaluates to true
一切都很好,没有错误。但是这意味着你的条件
arg==='a'
永远不会满足,因为
子测试中没有成员
a
,这就是为什么TS不能假设在我们使用
a
的条件内,因为在这种情况下,这个分支是完全不可到达的,并且在它的内部将是类型
永远不
。我们甚至可以编写这样的函数并检查:

const arg: SubTest = 'b'
foo(arg)
好的,但即使TS没有缩小到
a
,因为条件很清楚,任何通过它的东西都将是
a
,这里毫无疑问

让我们尝试手动复制原始条件中存在的相同类型的保护,该条件检查左侧值(从测试扩展)是否等于右侧值(从测试扩展)

函数isTestMember(x:x,y:y):x是y{
返回x==y//错误我们无法将x的成员与y的成员进行比较
}
正如你所看到的,这样的字体保护甚至不能被书写。由于X和Y不能重叠,因此条件
X===Y
X
Y
的所有成员无效


<> P.Ts不能考虑类型不能重叠的条件作为类型守卫,因此类型没有变窄。< /P>有趣。如果您编写了
arg:string
,那么它确实正确地缩小了范围,因此它肯定与T是一个类型变量有关。但是如果你没有一个
extends
子句,那么它认为
t
string
没有重叠,所以无法测试它是否是由
extends
引起的。这看起来像一个bug,但可能是有原因的。虽然问题本身可能很有趣,但上面示例中的泛型是无用的。只需使用函数foo(arg:Test).
@AlekseyL。您可以假设这只是一个演示问题的例子,而不是实际的用例。如果您定义
函数isTestMember(x:Test,y:y):x是y{return x==y}
,那么
foo
函数工作正常,并且
arg
If&/code>块内被推断为类型
T'a'
。因此,我认为对于某些
t
来说,条件并不总是可以满足这一事实并不重要。但是x不是Test,而是
t扩展Test
,那又怎样
x
可分配给
Test
,因为
x:T
T扩展了Test
。仅仅因为
T&'a'
可能没有填充,并不意味着我们不能在适当的类型保护之后将
x
缩小到该类型;在这里,工作没有错误。在这种情况下,
isTestMember
调用的返回类型被推断为
x是'a'
,它将
x
的范围缩小为
T&'a'
,因此问题是为什么
arg===='a'
的工作方式不一样。
T&'a'
可以计算为
never
,当我们有像
子测试
这样的类型时,它将完全是
从不
T&a
与just
T
function foo(arg: SubTest) {
  if (arg === 'a') { // compilation error, condition will be always false
    console.log(arg);
  }
}
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
}