#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:
Использование предиката типа теоретически может быть близким, поскольку это может быть любая функция предиката. Это не точная просьба, но она может помочь осуществить желание.
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');
}
Другим аналогичным способом может быть использование перечислений, поскольку они являются одним из артефактов машинописного текста, которые сохраняются во время выполнения. Использование перечисления таким образом не идеально и немного хрупко.
enum Types {
A,
B,
C
}
const isAorB = (x: AorBorC): x is AorB => {
return x.type < Types.C
}