This package exposes a really simple type called Id
.
type Id x
= Id String
Its for when your data has an id. Such as..
import Id exposing (Id)
type alias User =
{ id : Id ()
, email : String
}
Id
and not a String
?The Elm compiler is totally okay with the following code snippet..
viewUser : String -> String -> Html Msg
viewUser email id =
-- first parameter is email
-- second parameter is id
view : Model -> Html Msg
view model =
div
[]
[ viewUser
-- woops! The parameters are mixed up
model.user.id
model.user.email
]
These mistake is really easy to make and they cause real problems, but if you just use an Id
you can make them impossible.
x
in Id x
for?You understand the problem in the previous example right? Here is a very similar problem..
type Id
= Id String
updateUsersCatsFavoriteFood : Id -> Id -> Id -> Cmd Msg
updateUsersCatsFavoriteFood userId catId foodId =
-- ..
Theres absolutely nothing stopping a developer from mixing up a catId
with a userId
or a foodId
with a catId
.
Instead we can do..
type Id x
= Id String
updateUsersCatsFavoriteFood : Id User -> Id Cat -> Id Food -> Cmd Msg
updateUsersCatsFavoriteFood userId catId foodId =
-- ..
Now with Id x
, it is impossible (again) to mix up a Id User
with a Id Cat
. They have different types. And the compiler will point out if you try and use a Id User
where only a Id Cat
works.
The following code is not possible due to a circular definition of User
..
type alias User =
{ id : Id User }
Easy work arounds include..
type UserId
= UserId (Id User)
type alias User =
{ id : UserId }
and
type User
= User { id : Id User }
..but I would encourage you to build your architecture such that data does not contain its own Id x
to begin with. Instead, get used to operating on (Id User, User)
pairs, and treat the left side as the single source of truth for that identifier.
( Id User, User )
fromString : String -> Id x
Make an id from a string
Id.fromString "vq93rUv0A4"
toString : Id x -> String
Extract the string from an id.
encode : Id x -> Json.Encode.Value
Encode an Id
Encode.encode 0 (Id.encode id)
-- ""hDFL0Cs2EqWJ4jc3kMtOrKdEUTWh"" : String
[ ("id", Id.encode id) ]
|> Encode.object
|> Encode.encode 0
-- {\"id\":\"hDFL0Cs2EqWJ4jc3kMtOrKdEUTWh\"} : String
decoder : Json.Decode.Decoder (Id x)
Decode an Id
Decode.decodeString (Decode.field "id" Id.decoder) "{\"id\":\"19\"}"
-- Ok (Id "19") : Result String Id
generator : Random.Generator (Id x)
A way to generate random Id
s
import Id exposing (Id)
import Random exposing (Seed)
user : Seed -> ( User, Seed )
user seed =
let
( id, nextSeed ) =
Random.step Id.generator seed
in
( { id = id, email = "Bob@sci.org" }
, nextSeed
)