Reputation: 422
interface A = {
name: string;
...
};
interface B = {
name: string;
...
};
interface C = {
key: string;
...
};
type UnionOfTypes = A | B | C | ...;
function hasName(item: UnionOfTypes) {
if ("name" in item) {
item; // typescript knows here that item is either A or B
}
}
Is there some way that I can infer types in the same way that if("name" in item)
does it? I don't have classes only interfaces/types.
So that I don't have to explicitly say
function hasName(item: UnionOfTypes): item is A | B {
...
}
The reasoning behind this is that I want to use other type guards deeper down, or is there some other reason why I should avoid narrowing down types this way?
Upvotes: 1
Views: 1398
Reputation: 249506
There is no support for this by default in typescript. You can create a helper function that creates a type guard. The function passed to this helper function will return the guarded item, or false
.
function guard<T extends I, I>(fn: (value: I) => T | false) {
return function (value: I) : value is T {
return fn(value) !== false
}
}
interface A {
name: string;
a: number;
};
interface B {
name: string;
b: number;
};
interface C {
key: string;
};
type UnionOfTypes = A | B | C ;
const hasName = guard(function (item: UnionOfTypes) {
if ("name" in item) {
return item;
}
return false;
})
// Works for other casses too
let numberOrNull: Array<string | null> = ["", null]
let r = numberOrNull.filter(guard(v => v ?? false));
let r2 = numberOrNull.filter(guard(v => v ?? false));
Upvotes: 2