Cover image for TypeScriptのArray.filterで'Object is possibly undefined'を消したい
typescript

TypeScriptのArray.filterで'Object is possibly undefined'を消したい

March 25, 2019

2 min read

mitsuruogMitsuru Ogawa

TypeScript の小ネタです。

次のような基本的な Array の map 処理を考えてみましょう。 TypeScript のコンパイラオプションにはstrictNullChecksを入れています。

interface User {
  id: number;
  name?: string;
}

const users: User[] = [
  { id: 1, name: "aaa" },
  { id: 2 },
  { id: 3, name: "bbb" },
];

users
  .filter((user) => Boolean(user.name))
  // Object is possibly 'undefined'... why?
  .map((user) => console.log(user.name.length));

Userクラスの name は Optional なので、一度filter関数を通過させて undefined のものを除外しています。 しかし、TypeScript のコンパイラはしつこくObject is possibly 'undefined'と言ってきます。

今回は、これをどうにかしたいです。

User-Defined Type Guards を使う

このエラーを解消するためにはType Guardsを使って、コンパイラに型情報を追加で教える必要があります。

1 つめのやり方は、name が Optional ではない新しい Type を作る方法です。

...

// Userを継承した新しいTypeを作る
interface ConfirmedUser extends User {
  name: string;
}

users
  .filter((user: User): user is ConfirmedUser => Boolean(user.name))
  .map(user => console.log(user.name.length));

もう 1 つのやり方は、TypeScript にビルトインされている mapped-type のRequired<T>を使います。

...

users
  .filter((user: User): user is Required<User> => Boolean(user.name))
  .map(user => console.log(user.name.length));

Required<T>を使う場合は全てのプロパティが required になるので、部分的に Optional が残る場合は、最初のextendsで新しい Type を作るほうがいいと思います。

疑問に思ったので、ここで聞いてみた内容でした。