Programming TypeScript ch7 Handling Errors

TypeScript勉強メモ

出典: 


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>を返せない。