≪ Today I learned. RSS購読
公開日
タグ
Programming
著者
ダーシノ(@bc_rikko)

Parse, don't validate(型駆動設計)のメリット

Parse, don’t validateを読んだので、そこで理解した内容をまとめる。

Parse, don’t validateとは、データを単に検証(validate)するのではなく、解析(parse)して適切なデータ型や構造に変換しようという考え方だ。

Validate

まずは検証だけを行う場合を考えてみる。

type Item = { label: string, price: number }
function isValidItem(item: unknown): boolean {
  if (!item) {
    return false
  }

  if (typeof item !== 'object') {
    return false
  }

  if (Object.hasOwn(item, 'label') === false) {
    return false
  }

  if (Object.hasOwn(item, 'price') === false) {
    return false
  }

  return true
}

const res = api.get('...')
if (isValidItem(res)) {
  const item = res as Item
}

isValidItem()は、検証するだけ(booleanを返すだけ)で型を保証してくれるわけではない。 そのため、if文を通過したあとにバグを引き起こす可能性がある。

※TypeScriptにはType Predicateという機能があるので、やろうと思えば型を保証できる。

// TypeScriptのType Predicate機能を使った場合
function isValidItem(item: unknown): item is Item {
  ...
}

Parse

解析して適切なデータに変換する場合を考えてみる。

function parseItem(item: unknown): Item {
  if (!item) {
    throw new Error('item is required')
  }

  if (typeof item !== 'object') {
    throw new Error('item must be an object')
  }

  if (Object.hasOwn(item, 'label') === false) {
    throw new Error('item.label is required')
  }

  if (Object.hasOwn(item, 'price') === false) {
    throw new Error('item.price is required')
  }

  return item as Item
}

const res = api.get('...')
const item = parseItem(res)

parseItem()は検証と解析を同時に行うため、戻り値に意味(型)を持たせることができる。 そのため、以降のコードで型チェックが不要になり、バグを防ぎやすくなる。また、このようにParseすることで、あり得ない状態を排除できるので、コードやテストが書きやすくなる。