この記事の概要
Selectコンポーネントを自作しようとして、defaultValue
とoptionとして渡ってくる要素のvalueが一致していないとエラーが出るようにしたかったです。
備忘録がてら記事にしました。
環境
TypeScript 5.4以降
(記事内で使っているNoInfer
はTypeScriptの5.4から使用できます)
実装
import { ComponentProps } from "react";
type SelectOption<T extends string> = {
label: string;
value: T;
};
type Props<T extends string> = ComponentProps<"select"> & {
defaultValue?: NoInfer<T>;
label: string;
options: readonly SelectOption<T>[];
placeholder?: string;
};
export function Select<T extends string>({
defaultValue,
label,
options,
...props
}: Props<T>) {
return (
<div>
<label>{label}</label>
<select
defaultValue={defaultValue ?? ""}
{...props}
>
{placeholder ? (
<option value="" disabled>
{placeholder}
</option>
) : null}
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
);
}
型に適合しない場合
例えば以下の場合はdefaultValueのpink
がoptionsのvalueの中にありません。
<Select
label="セレクト要素のラベル"
defaultValue="pink"
helperText="ヘルパーテキスト"
options={[
{ label: "Red", value: "red" },
{ label: "Blue", value: "blue" },
{ label: "Green", value: "green" },
]}
/>
その場合以下のように怒られます。
Type '"pink"' is not assignable to type '((string | number | readonly string[]) & ("red" | "blue" | "green")) | undefined'.