Reputation: 2933
In making some code strict-mode compliant, I often run into a pattern like:
interface Item {
foo?: Foo;
}
interface Foo {
bar: string;
}
declare const items: Item[];
items.filter(item => !!item.foo).map(item => item.foo.bar); // ERROR! item.foo is possibly Undefined
This creates an error with --strictNullChecks
, since the information that item.foo
is defined does not get propagated.
In general, I've been creating one-off type guards to handle something like this.
function hasFoo(item: Item): item is Item & { foo: Foo } {
return !!item.foo;
}
items.filter(hasFoo).map(item => item.foo.bar);
But that's an awful lot of custom code to define for every single type I use this pattern on. Is there some way to write a function that returns a custom type guard?
I would love to write something like:
items.filter(hasField('foo')).map(item => item.foo.bar);
Upvotes: 0
Views: 176
Reputation: 2933
You can write a high-order function that returns a user-defined type guard. You might consider this a user-defined type guard factory.
function hasField<T, K extends keyof T>(key: K) {
return (item: T): item is (T & Required<Pick<T, K>>) => {
return typeof item[key] !== 'undefined';
}
}
With usage like:
items.filter(hasField('foo')).map(items => items.foo.bar);
This will assert that the given field is available, and that it is not undefined.
Upvotes: 1