TL;DR
keyDown
function accepts another function as an argument and returns an attribute, which Elm's renderer uses to attach an event listener.
If you define a type
type Msg
= KeyDown Int
The KeyDown
acts as a constructor function for values of type Msg
, so we can say that the implicit type of it is KeyDown: Int -> Msg
, which is what you want when you want to retrieve a key code from a DOM Event.
Explanation
First of all, I must say that the proper implementation should look like this:
keyDown : (Int -> msg) -> Attribute msg
keyDown tagger =
on "keydown" (Json.Decode.map tagger keyCode)
It is important to have msg
type variable in the signature, so it's possible to use this event listener in different parts of the application, where Html
emits different types of msg
To understand what is happening here, let's look closer at Html.Events.on
on : String -> Decoder msg -> Attribute msg
Every DOM event is represented as a JavaScript object with certain fields. To retrieve the data from JavaScript, Elm needs to pass it through a Decoder to ensure type safety in runtime, just like with HTTP requests.
The decoder in on
is expected to produce the same type of message, as the attribute itself.
By default, keyCode decoder decodes an Int
value, but what we want is to emit some message.
That's where Json.Decode.map helps us to get the Int
and apply some tagger
function, which produces a message.
Decoder
The entire (Json.map event keyCode)
part is essentially a Decoder msg
, which is applied to the event object to extract the key code and "tag" it with a message.