打字稿:“关注”条件类型

Posted

技术标签:

【中文标题】打字稿:“关注”条件类型【英文标题】:Typescript: 'Follow' conditional type 【发布时间】:2020-06-25 11:38:20 【问题描述】:

Typescript 有什么方法可以推断出b 也属于U extends Foo ? string : number 类型?如果aU extends Foo ? string : number 类型,那么在真正的分支中向字符串添加一个数字将导致字符串。在 false 分支中,将一个数字添加到 number 最终将成为一个数字。因此,我希望b 的类型也可以推断为U extends Foo ? string : number。或者这是一个错误的假设?

当我运行下面的 sn-p 时,出现以下错误:

运算符 '+' 不能应用于类型 'U extends Foo ?字符串:数字'和'数字'。(2365)

interface Foo 
  propA: boolean;
  propB: boolean;


declare function f<T>(x: T): T extends Foo ? string : number;

function foo<U>(x: U, d: number) 
  const a = f(x);
  const b = a + 2;


Playground Link

【问题讨论】:

错误是告诉你不应该在字符串中添加数字。 您可以在字符串中添加数字。这会产生一个字符串。 Typescript 对此没有任何问题:Playground Link 不使用工会:function add(s: string | number) return s + 1; // Error a 是条件类型,不是联合类型 只是不要 - dev.to/macsikora/this-is-why-typescript-restricts-operator-i0f 【参考方案1】:

Typescript 在这里报错不是因为 javascript 代码在运行时会失败,而是因为根据类型注释,这段代码有时会进行字符串连接,有时会进行算术运算,这通常意味着程序员犯了错误。

当你写+ 时,你几乎总是打算要么它意味着字符串连接,要么你打算它意味着算术,但你很少打算它可能意味着两者。因此,这是一个警告代码可能错误的错误。

如果你真的想要一个+,它有时会进行字符串连接,有时会进行算术运算,你可以在该行之前添加一个@ts-ignore 注释。这类似于Java中的@SuppressWarnings;您是在告诉编译器不要警告您通常表明错误的事情,因为在这种情况下这不是错误,您不需要编译器警告您。

function foo<U>(x: U, d: number) 
  const a = f(x);
  // @ts-ignore
  const b = a + 2;

【讨论】:

a as any 也很丑,但至少是语言结构 a as any 有什么实际好处吗?类型断言通常应用于 Typescript 不知道正确类型的情况(通常当它推断出比其他推理可能更弱的类型时)并且程序员知道正确的类型。在这种情况下,Typescript确实知道a的正确类型,所以程序员和编译器不会就它的类型产生分歧,他们不同意“有时连接,有时做算术”是否是一个错误.所以我会在这里使用@ts-ignore,因为它更符合否决编译器的原因。【参考方案2】:

该问题与 TS 中 + 运算符的严格行为有关。 TS 绝不允许在结果可能超过主要类型string 或主要类型number 的情况下使用+。函数foo 以这样的方式使用+,结果类型是联合string | number,因为函数是多态的,如果参数x 扩展Foo,那么如果不是@,我们将得到string 987654332@。

f 级别呈现的条件类型不会评估为foo 中的最终类型,不是,因为我们在此级别有类型变量U。如果在下面的示例中明确给出类型,它将被评估为特定类型:

// types provided directly
const x =  f(1) // number
const y = f(propA: true, propB: false) // string

function inside<U>(a:U) 
  const x =  f(a) // T extends Foo ? string : number // not evaluated
  return x + 1; // error


function insideButExactBranch<U extends Foo>(a:U) 
  const x =  f(a)
  return x + 1; // ok no error

foo 中,我们仍然使用未知的U,这就是为什么f 的结果被认为是任何可能的,这意味着-string | number。如果是这样,+ 将无法编译。

换句话说-TS无法评估f函数的结果,因此它从条件类型中获取所有可能的返回类型,这意味着联合string | number。更多关于为什么在 TS 中使用 + 受到限制 - Why TypeScript restricts + operator

【讨论】:

以上是关于打字稿:“关注”条件类型的主要内容,如果未能解决你的问题,请参考以下文章

打字稿条件类型内部类型

对象打字稿中的条件类型

具有默认参数值的打字稿条件返回类型

如何在打字稿中访问嵌套条件类型

为啥即使我有评估数据的条件,打字稿也会抱怨类型?

打字稿:检查类型是不是为联合