Условный род c тип - PullRequest
       82

Условный род c тип

0 голосов
/ 06 августа 2020

Я написал один и тот же код дважды с разной типизацией, но они идентичны.

Первый скомпилированный:

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)

Вопрос

Почему во втором коде ошибка? Как исправить набивки?

1 Ответ

0 голосов
/ 06 августа 2020

В вашем первом примере B расширяет логическое значение. Это позволяет Typescript более строго определять тип и позволяет уменьшить B до true или false по мере необходимости. Рассмотрим:

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 -типы

...