Invalid type specification for function

Hi all

I have a function with following spec definition:

  @spec parse_json_struct(String.t) :: %{firstname: String.t, lastname: String.t}
  def parse_json_struct(value) do
   map = Poison.Parser.parse!(value)
   map = map["d"]
   %{firstname: Map.fetch(map, "Firstname"), lastname: Map.fetch(map, "Lastname")}
  end

The dialyzer complain:

lib/auth/user_login.ex:42: Invalid type specification for function 'Elixir.SapOdataService.Auth.UserLogin':parse_json_struct/1. The success typing is (binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])) -> #{'firstname':='error' | {'ok',_}, 'lastname':='error' | {'ok',_}}

What is wrong?

Thanks

The problem was the map.fetch function, the return type is {:ok, _} not a binary.

3 Likes

That’s because Map.fetch(map, key) returns {:ok, value} if key can be found in given map, and :error otherwise. Dialyzer detects actual return type of your function and tells you that it doesn’t match your typespec.

Actual return type (detected by dialyzer):

%{firstname: {:ok, String.t} | :error, lastname: {:ok, String.t} | :error}

If you’d like to get bare value and fail if the key cannot be found in a map, try using Map.fetch!/2. You can also use Map.get/3 which will return a bare value if given key is in the map, and some default value otherwise.

3 Likes