Reputation: 6348
I have two related types and I want to distinguish between them with a custom type guard. They are generic types (in real life they take multiple type args but this is simplified for SO).
My question is this: is it possible to write a generic isCat
type guard that returns a predicate that works (returns true) for any cat type Cat<T>
? In my real app there are many possible options for T
so writing them all out isn't practical.
class Dog<T> {
age: number|T = 1
bark() { console.log("woof")}
}
class Cat<T> {
age: number|T = 1
meow() { console.log("meow")}
}
function isCat(animal: any): animal is Cat { // this is invalid, generic type Cat requires 1 arg
return 'meow' in animal
}
function f(animal: any) {
if (isCat(animal))
animal.meow()
}
f(new Cat<number>())
f(new Dog<number>())
Upvotes: 1
Views: 169
Reputation: 23575
You can use the reserved word unknown
to tell typescript that it's a Cat that have an unknown templated parameter
class Dog<T> {
age: number|T = 1
bark() { console.log("woof")}
}
class Cat<T> {
age: number|T = 1
meow() { console.log("meow")}
}
function isCat(animal: any): animal is Cat<unknown> {
return 'meow' in animal;
}
function f(animal: any) {
if (isCat(animal))
animal.meow()
}
f(new Cat<number>())
f(new Dog<number>())
Also I would do something like :
class Animal<T> {
age: number|T = 1
}
class Dog<T> extends Animal<T> {
bark() {
console.log('woof');
}
}
class Cat<T> extends Animal<T> {
meow() {
console.log('meow');
}
}
function isCat(animal: Animal<unknown>): animal is Cat<unknown> {
return 'meow' in animal;
}
function f(animal: Animal<unknown>) {
if (isCat(animal))
animal.meow()
}
f(new Cat<number>())
f(new Dog<number>())
Upvotes: 3