🫥

Typescriptでfindの返り値の型が<| undefined>であることへの対処

2023/08/05に公開

以下のような状況のとき,findの返り値の型は,<Item | undefined>になるが,selectedItemの型は,<Item | null>であるので,型が一致せずエラーになる.

export type Item = {
  id: number;
  name: string;
};

export const useSelectItem = () => {
  const [selectedItem, setSelectedItem] = useState<Item | null>(null);

  const onSelectItem = useCallback((props: Props) => {
    const { id, items } = props;
    const targetItem = items.find((item) => item.id === id);
    setSelectedUser(targetItem); // error
  }, []);
  return { onSelectItem, selectedItem };
};

解決法1

undefinedになりうる可能性のある値の直後にIF文で分岐を作って,Undefinedの場合の処理を書く.

export const useSelectItem = () => {
  const [selectedItem, setSelectedItem] = useState<Item | null>(null);

  const onSelectItem = useCallback((props: Props) => {
    const { id, items } = props;
    const targetItem = items.find((item) => item.id === id);
    if (targetItem === undefined) {
      console.error('item does not exist')
      // 何らかのエラー処理
      return;
    }
    setSelectedUser(targetItem);
  }, []);
  return { onSelectItem, selectedItem };
};

解決法2

targetItemの値がNullまたはUndefinedであれば,nullを明示的に設定することで型不一致を回避する.
(A ?? B)は,AがNullまたはUndefinedのとき,Bが実行される.

export const useSelectItem = () => {
  const [selectedItem, setSelectedItem] = useState<Item | null>(null);

  const onSelectItem = useCallback((props: Props) => {
    const { id, items } = props;
    const targetItem = items.find((item) => item.id === id);
    setSelectedUser(targetItem ?? null);
  }, []);
  return { onSelectItem, selectedItem };
};

解決法3

targetItemがUndefinedになる可能性はない,とTypescriptのコンパイラに伝える.
変数名!で,その値がUndefinedになることはないと伝える.

export const useSelectItem = () => {
  const [selectedItem, setSelectedItem] = useState<Item | null>(null);

  const onSelectItem = useCallback((props: Props) => {
    const { id, items } = props;
    const targetItem = items.find((item) => item.id === id);
    setSelectedUser(targetItem!);
  }, []);
  return { onSelectItem, selectedItem };
};

Discussion