Filtering with TypeScript Type Guard
I want to return processed data that could end up with falsy items in an array, but still want the returned array to be of its desired return type, TypeScript will complain:
type RawData = {
id: undefined | string;
value: number;
};
type ProcessedData = {
id: string;
value: number;
};
const processData = (rawData: RawData[]): ProcessedData[] =>
rawData
.map(({ id, value }) => (!!id ? { id, value } : undefined))
.filter(Boolean);
It will result in this error:
Type '({ id: string; value: number; } | undefined)[]' is not assignable to type 'ProcessedData[]'.
Type '{ id: string; value: number; } | undefined' is not assignable to type 'ProcessedData'.
Type 'undefined' is not assignable to type 'ProcessedData'.ts(2322)
It can be fixed by using a more specific type guard function
const processData = (rawData: RawData[]): ProcessedData[] =>
rawData
.map(({ id, value }) => (!!id ? { id, value } : undefined))
.filter(predicate);
const predicate = (
maybeProcessedData: ProcessedData | undefined
): maybeProcessedData is ProcessedData =>
typeof maybeProcessedData !== 'undefined';
Written another dem:
const typeSafeDropFalsy = <T>(
maybeValue: T | undefined | null
): maybeValue is T =>
maybeValue !== undefined && maybeValue !== null ? !!maybeValue : false;
type Person = { name: string };
const maybePersons = [{ name: 'alice' }, undefined, null, { name: 'sugar' }];
function acceptPerson(person: Person) {
console.log('accepting ', person.name);
}
function reviewGuests() {
maybePersons.forEach(acceptPerson);
maybePersons.filter(typeSafeDropFalsy).forEach(acceptPerson);
}