When defining types in an Elixir module, is it possible to merge two different map types, where one is a subset of the other? For example:
defmodule Test do
@typep map_a :: %{foo: String.t(), bar: String.t()}
@typep map_b :: %{foo: String.t(), bar: String.t(), baz: String.t()}
end
I’d like to indicate that the map_b type is a map that is essentially an instance of map_a() plus the additional baz key. I experimented with Map.merge(map_a(), %{baz: String.t}) – that compiles, but when I inspect the types via t(Test), I just get back exactly what I wrote,
@typep map_b :: Map.merge(map_a(), %{baz: String.t})
which doesn’t really give me insight into whether or not this really does what I’m hoping it does.
Is using Map.merge/2 (or anything similar) to combine custom map types a valid approach? If not, how might this be accomplished?
Thanks much.
>Solution :
Map.merge/2 won’t work for specs, it’s not a map actually, it’s just a similar syntax.
One might achieve the desired result with a bit of metaprogramming.
defmodule Test do
@map_a_type quote(do: [foo: String.t(), bar: String.t()])
@typep map_a :: %{unquote_splicing(@map_a_type)}
@typep map_b :: %{unquote_splicing(@map_a_type), baz: String.t()}
end