首页 > 解决方案 > 条件泛型类型

问题描述

我用不同的类型写了两次相同的代码,但它们是相同的。

第一次编译:

type X<B extends boolean> = { b1: B } & (B extends true ? { a1: 1 } : { a2: 2 })

function f<B extends boolean>(x: X<B>) {
  console.log(x)
}

function f2(b: boolean) {
  f(b ? { b1: true, a1: 1 } : { b1: false, a2: 2 })
}

f2(true)

以下有错误:

type X<B extends { b1: boolean }> = { b1: B['b1'] } & (B['b1'] extends true ? { a1: 1 } : { a2: 2 })

function f<B1 extends boolean>(x: X<{ b1: B1 }>) {
  console.log(x)
}

function f2(b: { b1: boolean }) {
  f(b.b1 ? { b1: true, a1: 1 } : { b1: false, a2: 2 })
                                 ^^^^^
                                 ERROR ts(2345)
}

f2({ b1: true })

错误:

Argument of type '{ b1: true; a1: number; } | { b1: false; a2: 2; }' is not assignable to parameter of type 'X<{ b1: boolean; }>'.
  Type '{ b1: true; a1: number; }' is not assignable to type 'X<{ b1: boolean; }>'.
    Object literal may only specify known properties, and 'a1' does not exist in type 'X<{ b1: boolean; }>'.ts(2345)

问题

为什么第二个代码有错误?我怎样才能解决打字问题?

标签: javascripttypescripttypescript-typingstypescript-generics

解决方案


在您的第一个示例中, B 扩展了布尔值。这允许 Typescript 更严格地推断类型,并允许 B 减少为之一truefalse根据需要。考虑:

const test: X<boolean> = {b1: true, a2: 2}; // Compiles. Likely not what you want
const test2: X<true> = {b1: true, a2: 2}; // Does not compile, as expected

这意味着当您调用 f2 时,类型{ b1: true, a1: 1 }实际上是X<true>,并且{ b1: false, a2: 2}X<false>

在该示例中,如果将结果分配给变量,它将无法编译,因为您将无法严格定义类型。

function f2(b: boolean) {
  const argument = b ? { b1: true, a1: 1 } : { b1: false, a2: 2 };
  // type is { b1: boolean; a1: number; a2?: undefined } | { b1: boolean; a2: number; a1?: undefined; }
  f(argument); // compile error
}

在您的第二个示例中,Typescript 只是没有足够的信息来评估编译类型的类型。

对您的第二个函数的此修改允许它编译

function f2(b: { b1: boolean }) {
  if (b.b1) {
    f({ b1: true, a1: 1 })
  } else {
    f({ b1: false, a2: 2 })
  }
}

有关条件类型的更多信息,请查看https://www.typescriptlang.org/docs/handbook/advanced-types.html#conditional-types


推荐阅读