Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

TypeScriptで配列からnullを取り除く

結論

const a = [1, 2, 3, null];
// nullとundefinedをはじく
const filtered = a.filter(<T>(n: T): n is NonNullable<T> => n != null);
// nullだけはじく
const filtered2 = a.filter(<T>(n: T): n is Exclude<T, null> => n !== null);

nullを除いた配列の型

nullを許容する配列があったとします。この配列にfilterをかけてnullをはじくコードは以下のようになります。

const a = [1, 2, 3, null];
const filtered = a.filter(n => n != null);

しかし、これだけではfilteredの型は(number | null)[]になります。filteredの型をnumber[]型にするにはasかisを使います。

const filtered = a.filter(n => n != null) as number[];
const filtered = a.filter((n): n is number => n != null);

これだけでもある程度は十分です。しかし、オブジェクトの配列であった場合、これだけでは不十分な場合があります。

type Obj = {
  hoge: string;
  fuga: number;
};
type ExObj = Obj & { piyo: boolean };
const objs: (Obj | ExObj | null)[] = [
  { hoge: "hoge", fuga: 3 },
  { hoge: "hoge", fuga: 3, piyo: true },
  null,
];
const filtered = objs.filter((n): n is Obj => n != null); // Obj[]型になって情報が失われる!

というわけで、もっときちんと型をつけましょう。

コード解説

const a = [1, 2, 3, null];
const filtered = a.filter(<T>(n: T): n is Exclude<T, null> => n != null);

ExcludeはUnion型Tを受け取り、TからUを除いたUnion型を返します。たとえばExclude<string | number | null, null>string | numberです。NonNullable<t>はTからnullとundefinedを除いた型を返します。

Exclude、NonNullableを使っているため、コードの意味もnullを除いたUnion型の手書きよりハッキリしています。

参考

参考というか、このページをもとに改良したのがこの記事です。