есть ли способ получить доступ к свойству типа объединения в виде массива значений для выполнения динамической проверки типа?

#typescript #typescript-typings

Вопрос:

в настоящее время я пишу код, подобный этому:

 interface A {
  type: 'A'
}

interface B {
  type: 'B'
}

interface C {
  type: 'C'
}

type AorBorC = A | B | C

type AorB = A | B

const returnOnlyAorBs = (x: AorBorC): AorB => {
  if (x.type === 'A' || x.type === 'B') {
    return x;
  }

  throw new Error('unexpected type');
}
 

какой тип отлично проверяет,

единственная проблема в том, что мой настоящий тип «AorBorC» — это гораздо больший союз.

Я бы очень хотел иметь возможность написать что-то вроде:

 const IdealReturnOnlyAorBs = (x: AorBorC): AorB => {
  if (AorB['type'].includes(x.type)) {
    return x;
  }

  throw new Error('unexpected type');
}
 

Мне кажется, что это может быть возможно, так как средство проверки типов прекрасно знает, что AorB['type'] такое, потому что я могу использовать его в качестве типа… Я знаю, как определять типы на основе массивов const, в основном я спрашиваю, возможно ли обратное.

Если нет, существуют ли какие-либо полезные шаблоны, которые могли бы упростить мой вариант использования? Т. е. безопасное сужение большого типа объединения до меньшего типа объединения.

Ответ №1:

Использование предиката типа теоретически может быть близким, поскольку это может быть любая функция предиката. Это не точная просьба, но она может помочь осуществить желание.

https://www.typescriptlang.org/play?ssl=27amp;ssc=2amp;pln=1amp;pc=1#code/JYOwLgpgTgZghgYwgAgILIN4ChnLATwAcIAuZAclXKwF8stRJZEUAhTHPI0i16uhuGjwkyAMIdcBYmXJj 9aSlQB7KKzUSAvGmQAfZOwNjF3NGvY70B1vQQqQAZzDJgj1euQ6AFAA8yHhpQYgCUZL6ujuaeWgB8krjIUBBgAK5QIMi AHRKXlo6AESohfoGOXkFRayFtHYOzkkp6SAA8iAANviBUT7 0UGhARZe8di4wDDI3m6BfiEhCbjJaRlZANycAlIAFlAqAO7IIBBHAKJQ 1De5KknvsQIkAAmXMTkIZs0QA

 const isAorB = (x: AorBorC): x is AorB => {
    return ["A", "B"].includes(x.type)
}

const returnOnlyAorBs = (x: AorBorC): AorB => {
  if (isAorB(x)) {
    return x;
  }

  throw new Error('unexpected type');
}
 

Другим аналогичным способом может быть использование перечислений, поскольку они являются одним из артефактов машинописного текста, которые сохраняются во время выполнения. Использование перечисления таким образом не идеально и немного хрупко.

https://www.typescriptlang.org/play?#code/KYOwrgtgBAKgngB2AZygbwFBSgQQDRZQBCB2AwhgL4YYCWIALsAE4BmAhgMbC7qEOJgALliDkAOhxUa9Jmy48ifbAKQj4SCUWl1GLDtyhllUVcNGbxFahjO4A9syKPjAXl4AfYlC8VbghycodxwfYhpOexBkBihaZBxHJXcACgAPEUSnFwBKETS41CzkgD4TbGZgBjBmECg08TsAHgsUKx1I6NjK6tqAeRAAGzhi1FSMwOdmMjzJ4LLMbFpWKBT44vScnPKoHpq6tIBuQhsVAAtmewB3KBBgG4BRZkvmFIByMDu0pE4mABNTII3jljpQgA

 enum Types {
  A,
  B,
  C
}

const isAorB = (x: AorBorC): x is AorB => {
    return x.type < Types.C
}