Returning Null
-
Pros
- 最もlightweightな方法
-
Cons
- 「なぜ失敗したか」の情報を欠く
- 「日付のパースに失敗しました」よりは「Ymdで入力してください」の方が親切
Throwing Exceptions
-
Pros
- なぜ失敗したかの理由を詰められる
-
Cons
- JavaScriptにはcatchのガードがないので単一のcatchの中でif-then-elseしないといけない
catch(e instanceof DateIsInTheFutureError)
- TypeScriptでは、例外は関数のシグネチャとして扱われない
- docコメントで、送出されうる例外を示すことはできる
- が、TSでこれを検査例外扱いしたりすることはできない
class MyError extends Error { }
/**
* @throws {MyError}
*/
function hoge(): number {
const rand = Math.random()
if (rand < 0.5) {
throw new MyError
}
return 1;
}
hoge(); // an exception might be thrown
Returning Exceptions
- 正常値と例外のunion typesを返す
-
Pros
- 型安全
-
Cons
- 冗長
- 呼び出し側は、戻り値を受け取って即座にエラー判定しないといけない
-
同じようなエラー判定コードまみれになる
if (res instanceof Error) { return res; }
The Option Type
Option<T>
,Try<T>
,Either<T,U>
とかの紹介- 概念自体は知ってるので略
- 自作しようの巻
-
書籍のものがテキトーすぎたので自前で書いた
- 型パズル完全に理解した
type NotNullOrUndefined = {}
class Just<T extends NotNullOrUndefined>{
constructor(private value: T) { }
flatMap(f: (value: T) => Nothing): Nothing
flatMap<U extends NotNullOrUndefined>(f: (value: T) => Just<U>): Just<U>
flatMap<U>(f: (value: T) => Maybe<U>): Maybe<U>
{
return f(this.value)
}
getOrElse(_: T): T {
return this.value
}
}
class Nothing {
flatMap(_: (value: never) => Nothing): Nothing
flatMap<U extends NotNullOrUndefined>(_: (value: never) => Just<U>): Nothing
flatMap<U>(_: (value: never) => Maybe<U>): Nothing
flatMap<U>(_: (value: never) => Nothing|Just<U>|Maybe<U>): Nothing
{
return this
}
getOrElse<T extends NotNullOrUndefined>(value: T): T {
return value
}
}
type Maybe<T> = T extends NotNullOrUndefined ? Just<T> : Nothing
function Maybe<T extends NotNullOrUndefined>(value: T): Just<T>
function Maybe(value: null | undefined): Nothing
function Maybe<T>(value: T): Maybe<T>
function Maybe<T>(value: T): Just<T>|Nothing|Maybe<T>
{
if (value == null) {
return new Nothing
}
return new Just(value)
}
const a = new Just(null) // Error. OK
const b = new Just(undefined) // Error. OK
const c = new Just(1) // Just<number>
const d = new Nothing // Nothing
const just = Maybe(1) // Just<number>
const nothing = Maybe(null) // Nothing
const maybe = Maybe(Math.random() < 0.5 ? null : 1) // Nothing | Just<number>
const maybe2 = Maybe(Math.random() < 0.5 ? 's' : 1) // Just<string | number>
const e = just.flatMap((_: number) => new Nothing) // Nothing
const f = just.flatMap((num: number) => new Just(num * num)) // Just<number>
const g = just.flatMap((_: number) => new Just('s')) // Just<string>
const h = nothing.flatMap((_: number) => new Nothing) // Nothing
const i = nothing.flatMap((num: number) => new Just(num * num)) // Nothing
const j = e.getOrElse(true) // true
const k = f.getOrElse(true) // number
const l = g.getOrElse(true) // string
const m = h.getOrElse(true) // true
const n = i.getOrElse(true) // true
- Conditional Typesを使って
Just<string|number>
をJust<string>|Just<number>
にバラすこともできる -
が、
flatMap<U>
が対応できないのでやめたT->Just<U>|Just<V>
を返せない。