Elixir
dialyzer

Elixirの静的型チェックの確認 - キーワードリストをつかった引数

キーワード引数をつかっている関数でもキーワードごとに型を指定したい。
指定できるか?

結論。
できるが構造的部分型だったとしてもエラーになる。
キーワードリストでなくて、Mapにしても同様。
なにか良い手はあるかもしれないが思いつかなかった。

確認

便宜上Flowと比較する

// @flow
function sample(hoge_with_goro: {hoge?: number, goro?: number}) {}

sample({}) // Ok
sample({hoge: 1}) // Ok
sample({goro: 2})  // Ok
sample({mogu: 3}) // Ok
sample({hoge: 1, goro: 2})  // Ok
sample({goro: 2, hoge: 1})  // Ok
sample({hoge: 1, mogu: 3}) // Ok
sample({hoge: 1, hoge: 11}) // Ok ({hoge: 11}と同じ)
sample({hoge: 1, goro: 2, mogu: 3}) // Ok

Elixirでやってみる。

defmodule Sample do
  @spec sample([hoge: integer, goro: integer]) :: nil
  def sample(hoge_with_goro), do: nil

  def test(), do: sample([]) # Ok goroもhogeもなくてもOK
  def test2(), do: sample(hoge: 1) # Ok goroが足りないのはOK
  def test3(), do: sample(goro: 2) # Ok hogeが足りないのはOK
  def test4(), do: sample(mogu: 3) # Error 指定してないものがあるとダメ
  def test5(), do: sample(hoge: 1, goro: 2) # Ok
  def test6(), do: sample(goro: 2, hoge: 1) # Ok 順番は自由
  def test7(), do: sample(hoge: 1, mogu: 3) # Error moguがあるからやっぱりだめ
  def test8(), do: sample(hoge: 1, hoge: 11) # 複数あっても大丈夫 (JSとはちがって複数値がある)
  def test9(), do: sample(hoge: 1, goro: 2, mogu: 3) # Error moguがあるからだめ
end

Mapだとoptionalやrequiredを指定できるので、optionalをつかってみる。
キーワードリストのときと基本的に一緒

defmodule SampleMap do
  @spec sample(%{optional(:hoge) => integer, optional(:goro) => integer}) :: nil
  def sample(hoge_with_goro), do: nil

  def test(), do: sample(%{}) # Ok
  def test2(), do: sample(%{hoge: 1}) # Ok
  def test3(), do: sample(%{goro: 2}) # Ok
  def test4(), do: sample(%{mogu: 3}) # Error
  def test5(), do: sample(%{hoge: 1, goro: 2}) # Ok
  def test6(), do: sample(%{goro: 2, hoge: 1}) # Ok
  def test7(), do: sample(%{hoge: 1, mogu: 3}) # Error
  def test8(), do: sample(%{hoge: 1, hoge: 11}) # Ok (%{hoge: 11}になってJSと同じ)
  def test9(), do: sample(%{hoge: 1, goro: 2, mogu: 3}) # Error
end

参考

関連