下記の記事を読んでいていて、どうしてもEither
が思い浮かんじゃったんですよね。
TypeScriptでany・unknown型の値を型セーフにハンドリングしたい
どういうことかと言うと、Either
っぽいコードを用意して、
.ts
type LambdaOfEither<T, U> = <V>(caseOf: CaseOfEither<T, U, V>) => V;
type CaseOfEither<T, U, V> = Readonly<{
left: (value: T) => V,
right: (value: U) => V
}>;
function left<T, U = never>(value: T): LambdaOfEither<T, U> {
return caseOf => caseOf.left(value);
}
function right<U, T = never>(value: U): LambdaOfEither<T, U> {
return caseOf => caseOf.right(value);
}
あとはswitch
文の機能に代わる高階関数を用意して、
.ts
const typeSwitch = left;
function typeCase<T, V extends T, U>(typeGuard: (value: T) => value is V, transformer: (value: V) => U): CaseOfEither<T, U, LambdaOfEither<T, U>> {
return {
left: value => typeGuard(value) ? right(transformer(value)) : left(value),
right
};
}
function typeDefault<U, V extends U>(defaultValue: V): CaseOfEither<unknown, U, U> {
return {
left: _ => defaultValue,
right: value => value
};
}
高階関数に食わせる関数を用意すれば、
.ts
function isBoolean(value: unknown): value is boolean {
return typeof value === "boolean";
}
function isNumber(value: unknown): value is number {
return typeof value === "number";
}
function isString(value: unknown): value is string {
return typeof value === "string";
}
似たようなのが実装できるじゃないですか。
.ts
function test(jsonString: string): boolean {
return typeSwitch(JSON.parse(jsonString))
(typeCase(isBoolean, value => value))
(typeCase(isNumber, value => value !== 0))
(typeCase(isString, value => value === "true" || value === "yes"))
(typeDefault(false));
}
["true", "false", "0", "1", "-1", "100", `"true"`, `"yes"`, `"hoge"`].map(test);
// => [true, false, false, true, true, true, true, true, false]
みなさんにも、こういう悪癖ありませんか?