nullable な Array を non-null に filter するとき
ふつうにこう書いたとして:
const nullables: (number | null)[] = [1, 2, 3, null, 4];
const nonNullables: number[] = nullables.filter(
(item: number | null) => item !== null
);
実質的には Array.prototype.filter 内で item !== null でフィルタしているので
nonNullables の要素はすべて non-null であるはずですが、
Type '(number | null)[]' is not assignable to type 'number[]'.
Type 'number | null' is not assignable to type 'number'.
Type 'null' is not assignable to type 'number'.
実際のところ、filter の返り値は依然 nullable として扱われてしまい、
エラーになってしまいます。
Type Predicate (型述語) を使う
Type Predicate を返すような関数 (Type Guard) を定義することで、
あるスコープでの型を保証すれば大丈夫です:
function notNull<T>(item: T | null): item is T {
return item !== null;
}
const nonNullables: number[] = nullables.filter(notNull);
// OK!
あるいは
const nonNullables: number[] = nullables.filter(
(item: number | null): item is number => item !== null
);
// OK!
null も通す
ただし、ヒューマンエラーで null を通してしまっても
それを静的に検出はされないことに気づきました:
function notNull<T>(item: T | null): item is T {
return item === null;
}
const nonNullables: number[] = nullables.filter(notNull);
// OK! (であってほしくない)
Advanced Types - User-Defined Type Guards では
A type guard is some expression that performs a runtime check that guarantees the type in some scope.
と書かれていますが、特に実行時にもチェックされてないように思います。
なぜだろう。
解決策があれば教えてください。