Фильтр для удаления неопределенных элементов не используется TypeScript

В следующем коде я бы не хотел добавлять undefinedкак аннотация типа для filterDevice. Я думаю, что filterDevice никогда не должно быть неопределенным, поскольку я отфильтровываю неопределенные устройства.

Но если я удалю undefined аннотации типа, TypeScript жалуется, что Type 'ICouchDBDocument | undefined' is not assignable to type 'ICouchDBDocument'.

devices
.filter((device: ICouchDBDocument | undefined) => Boolean(device)) //should filter away all undefined devices?
.map((filteredDevice: ICouchDBDocument | undefined) => { ... })

Как я могу изменить свой код, чтобы фильтр влиял на аннотацию типа?

1 ответ

Решение состоит в том, чтобы передать функцию защиты типов, которая сообщает TypeScript, что вы фильтруете undefined часть типа:

devices
.filter((device): device is ICouchDBDocument => Boolean(device)) //filters away all undefined devices!
.map((filteredDevice) => {
    // yay, `filteredDevice` is not undefined here :)
})

Если вам нужно делать это часто, вы можете создать универсальную служебную функцию, которая должна работать с большинством типов:

const removeNulls = <S>(value: S | undefined): value is S => value != null;

Вот некоторые примеры:

devices
.filter(removeNulls)
.map((filteredDevice) => {
    // filteredDevice is truthy here
});


// Works with arbitrary types:
let maybeNumbers: (number | undefined)[] = [];

maybeNumbers
    .filter(removeNulls)
    .map((num) => {
        return num * 2;
    });

(Я не использовал Boolean функционировать в removeNulls в случае, если люди хотят использовать его с number типы - иначе мы случайно отфильтруем ложь 0 значения тоже!)


Спасибо, какое-то время мне было интересно то же самое, но ваш вопрос побудил меня наконец-то разобраться:)

Глядя на TypeScript lib.es5.d.ts, то Array.filter функция имеет эту сигнатуру типа (на самом деле в файле их два, но это тот, который имеет отношение к вашему вопросу):

/**
 * Returns the elements of an array that meet the condition specified in a callback function.
 * @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array.
 * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
 */
filter<S extends T>(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];

Итак, ключ к этому - value is Sвозвращаемый тип callbackfn, который показывает, что это охранник определяемого пользователем типа.

Другие вопросы по тегам