33
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

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.

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

33
12
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?