#typescript
Вопрос:
У меня есть такой типаж:
type BaseType = {
type: string
id: string
}
Я создаю из него два типа:
type TypeA = {
type: 'TypeA'
}
type TypeB = {
type: 'TypeB'
}
Затем я создаю тип объединения TypeA
и TypeB
:
type ABTypes = TypeA | TypeB
Затем я создаю другой тип на основе BaseType
:
type TypeC = {
type: 'TypeC'
}
Теперь я хочу создать защиту типа для ABTypes
такого:
function isABTypes(
x: BaseType
): x is isABTypes {
// I don't want to do this:
return x.type === 'TypeA' || x.type === 'TypeB'
// nor:
return x.type !== 'TypeC'
}
Как я могу реализовать защиту типов без необходимости проверять type
свойство на наличие «TypeA» и TypeB
(которые здесь нетипизированы и не безопасны для рефакторинга)?
Я мог бы использовать это:
type Types = ABTypes['type']
что было бы 'TypeA' | 'TypeB'
.
Но это тип, а не строковый массив, который я могу использовать для сравнения.
Самое близкое, что я мог получить, это
const ABTypes = ['TypeA', 'TypeB']
function isABTypes(
x: BaseType
): x is isABTypes {
return ABTypes.inclues(x.type)
}
Но это все еще не очень надежно, когда добавляются новые случаи объединения.
Комментарии:
1. Определяемые пользователем типы защиты не проверяются на правильность, поэтому они по своей сути небезопасны в этом отношении, независимо от того, как вы их пишете. Я предлагаю, чтобы лучшее, что можно было сделать, — это всегда писать свои функции защиты типов непосредственно рядом с определением типа, для которого они тестируются, поэтому менее вероятно, что одна из них будет изменена без другой.
Ответ №1:
После нескольких итераций я добился именно этого. Я не уверен, что это именно то решение, которое вы ищете, но вам обязательно стоит взглянуть
// this is our base type
interface BaseType {
type: string;
id: string;
}
// a list of types
const ABTypes = ["TypeA", "TypeB"] as const;
// union created from above ABTypes -> type ABTypesUnion = "TypeA" | "TypeB"
type ABTypesUnion = typeof ABTypes[number];
// interface with fixed value of type
interface ABTypes extends BaseType {
type: ABTypesUnion;
}
// test
function isABTypes(x: BaseType): x is ABTypes {
return ABTypes.includes(x.type as ABTypesUnion);
}
const test: ABTypes = {
type: "TypeA",
id: "UX0001"
};
const isTestAB = isABTypes(test);
Вам не нужно поддерживать объединение отдельно.