compiler
compiler copied to clipboard
Elm Reactor should pass `flags: null`
Quick Summary: To develop apps with JS-Interop it would be great if reactor would set init to null, so that on the Elm side you can declare main like main: Program (Maybe <some-type>) Model Msg
.
Currently it doesn't set any value which means that undefined is returned, and this error will be shown
(1) Problem with the given value:
undefined
Expecting null
SSCCE
Try this in playground --
import Html exposing (text)
import Browser
main: Program (Maybe Int) Model Msg
main =
Browser.document
{ init = \a -> ({}, Cmd.none)
, view = \m -> { title = "t", body = [text "hi"]}
, update = \_ _ -> ({}, Cmd.none)
, subscriptions = \_ -> Sub.none
}
type alias Model = {}
type Msg = None
On a side note, I sort of expected to be able to do this:
type alias Undefined = ()
type Startup = Undefined | Maybe Int
main : Program Startup Model Msg
But that results in:
BAD FLAGS - Your `main` program wants a `Startup` value from JavaScript.
21| main =
#^^^^#
I cannot handle that. The types that CAN be in flags include:
Ints, Floats, Bools, Strings, Maybes, Lists, Arrays, tuples, records, and
JSON values.
Since JSON values can flow through, you can use JSON encoders and decoders to
allow other types through as well. More advanced users often just do everything
with encoders and decoders for more control and better errors.
Which is reasonable, but seems a bit inconsistent when ()
compiles with Program () Model Msg
.
Thanks for reporting this! To set expectations:
- Issues are reviewed in batches, so it can take some time to get a response.
- Ask questions in a community forum. You will get an answer quicker that way!
- If you experience something similar, open a new issue. We like duplicates.
Finally, please be patient with the core team. They are trying their best with limited resources.
type alias Undefined = ()
type Startup = Undefined | Maybe Int
type alias Undefined = ()
has no effect on the Startup
declaration. Startup happens to have a type constructor called Undefined
(which takes no parameters). The type alias Undefined
is not referenced anywhere and can be removed without changing anything.
Similarly, Maybe
is declared as a type constructor for Startup
in this example, and it takes an Int parameter - it happens to be called Maybe
but it does not use Elm's built in Maybe type.
type
in Elm works a lot differently than in TypeScript - basically it's for creating "tagged union" types (unlike with TS, you don't need to have an object with a special "determinant" field). Each option for the type (the first word) is your own custom type constructor function, while following words are types. For example:
type = Fruit String | Vegetable String | Other
means you can declare variables like this
apple = Fruit "Apple"
broccoli = Vegetable "Broccoli"
wheat = Other
If it was possible to have a fruit with no name, you could do:
type = Fruit (Maybe String) | Vegetable String | Other
apple = Fruit (Just "Apple")
secretFruit = Fruit Nothing
broccoli = Vegetable "Broccoli"
wheat = Other
This is how you'd use an Elm Maybe
in a custom type
.
For flags, you need to do something a bit more involved in order to accept data with different shapes... I'm not super knowledgeable with the different techniques for decoding flags so I'll stop here and just drop the Elm guide's link on them for convenience: https://guide.elm-lang.org/interop/flags.html
Hope this helps!
@adamdicarlo Thanks for replying. That makes sense. Let me rephrase my example so I can get some clarity.
What is this type known as, ()
?
And if I rewrite my example, then would this expression make sense,
type Startup = NoFlags () | Edit (Maybe Int)
So what I'm looking for is the ability to do this,
type Startup = NoFlags () | IntFlag (Maybe Int)
main: Program Startup Model Msg
...
The reason is because this is valid,
main: Program () Model Msg
and this is valid,
main: Program (Maybe Int) Model Msg
But the reason the second example wouldn't work in the playground is because the playground doesn't pass in null as a flag parameter, and by extension the reactor does not pass null as well. But if you were to write the html on your own and pass null it would work. But if you don't pass anything (undefined), then ()
is expected.
So I guess the limitation here is that main
(elm compiler) doesn't accept union-types as a flag parameter?