typescript: сбой защиты типа при объединении перечислений

#typescript

#машинописный текст

Вопрос:

Просто прочитайте о Type Guards главе в Typescript

Но почему мои следующие простые типы охранников не могут различить объединение enum?

 enum A {
  COMMA = ',',
  PLUS = ' '
}

enum B {
  REAL = 'REAL',
  STRING = 'STRING'
}

function notWork<T extends A | B>(val: T) {
  if(isA(val)) {
    // mark 1:
    console.log('isA:', useA(val))
  } else  {
    // mark 2: 
    // val should be in type B here !!!
    console.log('isB:', useB(val))
  }
}


function isA(token : A | B): token is A {
  return Object.values(A).includes(token as A)
}

function useA(v: A) {
  console.log("we're using A:", v)
  return v
}

function useB(v: B) {
  console.log("we're using B:", v)
  return v
}

 

в моем понимании:

  1. в mark 1 значение val на самом деле находится в type: (T amp; A.COMMA) | (T amp; A.PLUS) . это работает, но почему это не простой A
  2. в mark 2 вэл по-прежнему A | B , почему мои охранники типа потерпели неудачу?

Игровая площадка TS

Ответ №1:

Это потому isA(x) === false , что не означает, что x это a B , просто это не an A .

   

enum C {
  FOO = 'FOO',
  BAR = 'BAR'
}

 

function notWork<T extends A | B>(val: T) { // yes, not A | B | C

 

function isA(token : A | B | C): token is A {

 
 

Приводит к ошибке того же типа, но теперь понятно, почему isA это не означает, что это a B и не может быть a C .

Ваш isA метод может принимать любое объединение типов в качестве параметра. Это отличается от T in notWork .

Теперь, если вы передаете оба одинаковых типа, внезапно компилятор знает, что любой T , который не является an, A должен быть a B :

  

type T = A | B

 

function notWork(val: T) {

 

function isA(token : T): token is A {

 
 

Вот моя первая игровая площадка.
И второе.

Ответ №2:

Изменить подпись с:

 function notWork<T extends A | B>(val: T) { // ...
 

Для:

 function notWork(val: A | B) { // ...
 

И все будет работать так, как вы ожидали.