結論
as でオブジェクト型を定義してダウンキャストすれば良いです。
事の経緯
きっかけは Next.js でダイナミックルーティングの際に、router.query
を使用したのだが、返却型がstring | string[]
となります。
使用するコンポーネントに対して型エラーが起きたのでそれを解決する方法をメモとして残します。
import { useRouter } from "next/router";
export const ParentComponent = () => {
const router = useRouter();
// as により型をダウンキャストする
const { hoge, piyo } = router.query as {
hoge: string;
piyo: string;
};
return <ChildComponent hoge={hoge} piyo={piyo} />;
};
type ChildComponentProps = {
hoge: string;
piyo: string;
};
const ChildComponent: React.VFC<ChildComponentProps> = ({ hoge, piyo }) => {
return (
<>
<div>{hoge}</div>
<div>{piyo}</div>
</>
);
};
だめな例
型キャストがない状態だと以下のエラーが出力されます。
Type 'string | string[]' is not assignable to type 'string'.
Type 'string[]' is not assignable to type 'string'.ts(2322)
import { useRouter } from "next/router";
export const ParentComponent = () => {
const router = useRouter();
// hoge, piyoは 'string | string[]' 型
const { hoge, piyo } = router.query;
// ChildComponent の hoge はstring型なので Error
return <ChildComponent hoge={hoge} piyo={piyo} />;
};
他の方法
また分割代入したそれぞれの変数に対して、ChildComponent に渡す際にダウンキャストしても良いです。個人的にはなんかイケてない書き方な気もします。
import { useRouter } from "next/router";
export const ParentComponent = () => {
const router = useRouter();
const { hoge, piyo } = router.query;
return <ChildComponent hoge={hoge as string} piyo={piyo as string} />;
};
では number 型にキャストする場合はどうなのか?
子コンポーネントのPropsが以下の場合、numberにキャストする必要があります。
type ChildComponentProps = {
hoge: number;
piyo: number;
};
as unknown により型をアップキャストしダウンキャストするとうまく型エラーを回避できます。
import { useRouter } from "next/router";
export const ParentComponent = () => {
const router = useRouter();
// as unknown により型をアップキャストし、その後ダウンキャストする
const { hoge, piyo } = router.query as unknown as {
hoge: number;
piyo: number;
};
return <ChildComponent hoge={hoge} piyo={piyo} />;
};