jc00ke

jc00ke

Typespec for map w/both required and optional keys

Expanding on this topic: Map typespec question

Let’s say I have a map with required and optional keys. I’d like to document both, but based on the docs it seems like you can’t denote a specific key is optional. Where else do people document these optional keys?

@type params :: %{foo: String.t, optional(:atom) => integer()}
@doc """
Does a thing

## Examples

    iex> do_thing(params)
    {:ok, "thing_done"}

## Parameters

    %{
        foo: required(string),
        bar: optional(integer)
      }
"""
@spec do_thing(params) :: {:ok, String.t}
def do_thing(...), do: {:ok, "thing_done"}

With that example in mind, how do I specify in the @type params declaration that :bar is optional? Just leave it out and document its optionality in the @doc?

Thanks for the help!

Marked As Solved

NobbZ

NobbZ

Literals are their own type. So optional(:bar) is exactly that.

12
Post #6

Also Liked

OvermindDL1

OvermindDL1

Yep, use the union operator |. :slight_smile:

I.E. you specify the whole structure twice with each variation, like:

%{
  account_number: String.t(),
  :counterparty_id => integer(),
} | %{
  account_number: String.t(),
  receiver_account_number: String.t()
}

It’s a bit of a pain and combinatorially explosive, but it works. :slight_smile:

soup

soup

A potential stumbling block: even though the keys look like atoms, you can’t mix the x: and => when using optional. I assume this is because optional(:bar) resolves to a non-atom type.

You might get the somewhat cryptic error:

@type params :: %{
  foo: String.t(),
  optional(:bar) => integer() # "syntax error before: optional"
}

You must convert to:

@type params :: %{
  foo => String.t(),
  optional(:bar) => integer()
}

E: see below, or

@type params :: %{
  optional(:bar) => integer(),
  foo: String.t()
}
LostKobrakai

LostKobrakai

The syntax sugar for keyword lists as well as for atom keys in maps is only allowed trailing to elements not using the syntax sugar within the same map/list. Though I‘m not sure if the same does work in typespecs.

blatyo

blatyo

Conduit Core Team

Perhaps do it with the value.

@type parmas :: %{foo: String.t, bar: integer() | nil}

Or maybe:

@type optional_integer :: integer() | nil
@type parmas :: %{foo: String.t, bar: optional_integer()}
jc00ke

jc00ke

%{
  account_number: String.t(),
  optional(:counterparty_id) => integer(),
  receiver_account_number: String.t() unless :counterparty_id set
}

Since I have your attention (:wink:) is there a way to specify something is required if another key is not present? In this case, you can either have a :counterparty_id or several :receiver_* pairs.

Where Next?

Popular in Questions Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New

We're in Beta

About us Mission Statement