Context:
type NonFeline = 'Mouse' | 'Sheep';
type Feline = 'Lion' | 'Cat' ;
type AnimalInfo = {
Category: NonFeline;
Age: number;
} | {
Category: Feline;
Age: number;
Owner:string;
};
let x: AnimalInfo = getAnimal(1);
if(x.Category === 'Lion' || x.Category === 'Cat'){
console.log(x.Owner);
}
function getAnimal(i: number): AnimalInfo{
return i % 2 ? {
Category: "Lion",
Age: 10,
Owner: "Y"
} : {
Category: "Mouse",
Age: 1,
};
}
How can I be sure when later I added "Tiger" to Animal
type, no need to change to if
, or at least if
gives me a compile time typescript error?
To solve the runtime check use a set, extract values from it as a type and use a type predicate function (Set#has()
doesn't narrow unfortunately) to check whether AnimalInfo
is Feline
:
type SetValues<T extends Set<unknown>> = T extends Set<infer I> ? I : never;
const felineCategories = new Set(['Lion', 'Cat'] as const); // you add any new types here
const isFeline = (animal: AnimalInfo): animal is Feline => felineCategories.has(animal.Category as FelineCategory);
type FelineCategory = SetValues<typeof felineCategories>;
type AnimalCategory = 'Mouse' | 'Sheep';
type Animal = {
Category: AnimalCategory;
Age: number;
}
type Feline = {
Category: FelineCategory;
Age: number;
Owner:string;
}
type AnimalInfo = Animal | Feline;
declare const x: AnimalInfo;
if(isFeline(x)){
console.log(x.Owner);
}
An array version:
const felineCategories = ['Lion', 'Cat'] as const; // you add any new types here
const isFeline = (animal: AnimalInfo): animal is Feline => felineCategories.includes(animal.Category as FelineCategory);
type FelineCategory = typeof felineCategories[number];
type AnimalCategory = 'Mouse' | 'Sheep';
type Animal = {
Category: AnimalCategory;
Age: number;
}
type Feline = {
Category: FelineCategory;
Age: number;
Owner:string;
}
type AnimalInfo = Animal | Feline;
declare const x: AnimalInfo;
if(isFeline(x)){
console.log(x.Owner);
}