Help us understand the problem. What is going on with this article?

TypeScript で nullable な Array を non-null に filter する

More than 1 year has passed since last update.

nullableArray を non-nullfilter するとき
ふつうにこう書いたとして:

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.

と書かれていますが、特に実行時にもチェックされてないように思います。
なぜだろう。
解決策があれば教えてください。

mangano-ito
Web + アプリ (Android) エンジニアです。
https://mangano-ito.hatenablog.com/
hatena-corp
「知る」「つながる」「表現する」で新しい体験を提供し、人の生活を豊かにする
https://hatenacorp.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away