背景
関数で文字列以外も受け入れたいけど、特定の文字列も補完を効かせたいとき
Union型
const unionInput = (input: "hoge" | "fuga") => {
return input;
};
VSCode上でちゃんと補完されます。
動的な値を代入だとうまくいかない
例えばAPIから返ってくる値は、string
型になってしまうときが多いと思います。
const unionInput = (input: "hoge" | "fuga") => {
return input;
};
const resFromApi = { name: "hoge", age: 20 };
unionInput(resFromApi.name); // 型エラー
name
の値はhoge
ですが、string型になってしまうので、エラーを起こしてます。
Union に string 追加
const unionOrStringInput = (input: "hoge" | "fuga" | string) => {
return input;
};
unionOrStringInput("fuga");
unionOrStringInput("test"); // 範囲の広い string が優先されるので, hoge, fugaは補完されない
範囲の広いstring
に引っ張られ、補完が効かない
動機
関数を使う時は、補完を効かせたい
だけど、stringも受け入れたい
結論: Omit
を使ってできました
追記: string & {}
もできます(@sugoroku_y さんありがとうございます)
Omit
const unionOrStringOmitInput = (input: "hoge" | "fuga" | Omit<string, "hoge" | "fuga">) => {
return input;
};
string & {}
@sugoroku_y さんより
const unionOrStringOmitInput = (input: "hoge" | "fuga" | string & {}) => {
return input;
};
ちゃんと補完効いています。
@sugoroku_y さん、ありがとうございます。
ジェネリックにしてみた
上記のunionOrStringOmitInput
を汎用的に使えるように、ジェネリックで型を作ってみました。
// ジェネリックを使ってみたパターン
type StringOr<T extends string> = Input | Omit<string, T>;
type HogeOrFuga = "hoge" | "fuga";
const stringOrInput = (input: StringOr<HogeOrFuga>) => {
return input;
};
stringOrInput("fuga");
stringOrInput("test");
zodでやってみた
import { z } from "zod";
const HogeOrFugaSchema = z.enum(["hoge", "fuga"]);
type HogeOrFuga = z.infer<typeof HogeOrFugaSchema>;
const unionOrStringInput = (input: HogeOrFuga | Omit<string, HogeOrFuga>) => {
const parsed = HogeOrFugaSchema.safeParse(input);
return parsed.success ? parsed.data : "failed";
};
const resFromApi = { name: "hoge", age: 20 };
unionOrStringInput(resFromApi.name);
補完効いていいかんじです。
参考