💪
TypeScriptで引数の値によって戻り値の型を変える
概要
- 引数
flag = false
に渡す値によって戻り値の型を変える
例
例えば以下のような関数を実装しました。
何かしらの配列をもとに User
配列を作成して返します。
User
は公開情報と非公開情報をもっていて、そこから非公開情報を抜いた PublicUser
を定義します。
デフォルトでは PublicUser
を返し、 includePrivate
引数に true
を指定した場合に User
を返します。
export type User = {
pub1: string;
pub2: string;
pvt1: string;
pvt2: string
};
const pvts = ["pvt1", "pvt2"] as const;
export type PublicUser = Omit<User, (typeof pvts)[number]>;
export function parse(data: Record<string, string>[], includePrivate = false) {
return data.map((v: Record<string, string>, i: number) => {
const row = {
pub1: v.data1,
pub2: v.data2,
pvt1: v.data3,
pvt2: v.data4
};
if (!includePrivate) {
pvts.forEach((col) => delete row[col]);
}
return row;
});
}
parse([{}]);
// function parse(data: Record<string, string>[], includePrivate?: boolean): {
// pub1: string;
// pub2: string;
// pvt1: string;
// pvt2: string;
// }[]
parse([{}], false);
// function parse(data: Record<string, string>[], includePrivate?: boolean): {
// pub1: string;
// pub2: string;
// pvt1: string;
// pvt2: string;
// }[]
parse([{}], true);
// function parse(data: Record<string, string>[], includePrivate?: boolean): {
// pub1: string;
// pub2: string;
// pvt1: string;
// pvt2: string;
// }[]
この状態では includePrivate
を省略しても true
を指定しても戻り値は User[]
になります。
解決方法
引数の値からかっこよく推測する
こちらの記事では引数を参照してTypeScriptっぽくてかっこいいやり方が紹介されています。
もともとはこちらを参考に進めていたのですが、引数を省略可能にしたところでうまく効かなくなってしまい次の方法でやることになりました。
オーバーロード関数で引数のパターン分シグネチャを定義する
TypeScriptではひとつの関数に異なる関数シグネチャを複数持たせることができます。
この文法に従って includePrivate: true
の場合とそれ以外の場合でシグネチャを定義することで戻り値の型を引数の値によって変えることが出来ます。
export function parse(
data: Record<string, string>[],
includePrivate?: boolean
): PublicUser[];
export function parse(
data: Record<string, string>[],
includePrivate: true
): User[];
export function parse(data: Record<string, string>[], includePrivate = false) {
// ...
}
parse([{}]);
// function parse(data: Record<string, string>[], includePrivate?: boolean): PublicUser[] (+1 overload)
parse([{}], false);
// function parse(data: Record<string, string>[], includePrivate?: boolean): PublicUser[] (+1 overload)
parse([{}], true);
// function parse(data: Record<string, string>[], includePrivate: true): User[] (+1 overload)
少し(?)ブサイクですが、目的は達成できました。
まとめ
TypeScriptは難しい。
Discussion