7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Elm]Browser.Navigation.Key生成できない問題

Posted at

要約

Browser.Navigation.Keyは自分で生成できなくてテストなどで困るので以下のような型を作ってます

Types.elm
type WithKey m
    = WithKey Key m

以上です。ありがとうございました

問題提起

Elm0.19になって起動Program周りが整理されてBrowser packageに集約されました

この中のBrouwser.applicationではルーティングを行う際、Keyが必要になります

このKey型の値はinit関数に渡されるのでそこでよしなに自分のModelに含めることになります

Main.elm
type alias Model = { key : Browser.Navigation.Key, ... }

init : () -> Url -> Key -> ( Model, Cmd Msg )
init _ url key =
    ( { key = key
      , ...
      }
    , Cmd.none
    )

さて、何も問題はありませんね

Modelを引数にとる関数のテストをしたい

あなたの手元にはModelを引数に取る関数があり、これをあなたはテストしたいはずです
updateの中身を切り出した関数とか、Page用のviewとかですね

update msg model =
    case msg of
        ComplicatedMsg data ->
            complicatedUpdate data model
        ...

view model =
    case route of
        ListRoute ->
            listView model
        ...

わたしの場合はviewでKeyが問題になりました(コード)。わたしは自分で作ったBibliopolaというStorybook的なのでviewを見ながら開発してるのでModelが生成できないと使えなくなって困るんです

解決策1

問題を解決するのは難しいことではありません
引数にKeyが入ってるとはいえ別に使ってるわけではないので適切に引数の型を狭めればいいです

type alias Model =
    { key : Key
    , ham : Ham
    , egg : Egg
    }

-- view : Model -> Html Msg
view : { a | ham :Ham, egg : Egg } -> Html Msg
view model =
    ...

こんな感じ。構造的部分型とかいうのかな、まあ詳しくないので呼び方はなんでもいいのですがこれでこのview関数をテストするのにKeyは不要になりました

ついでにaliasしときましょう

type alias SubModel a =
    { a | ham : Ham, egg : Egg }

view : SubModel a -> Html Msg
view model =
    ...

よしこれでOkですね🎉

解決策2

SubModel aの型変数がうざい

解決策3も出てきますが型いじってるだけで大差ないのでお好きなものがあれば採用ください

アプリケーションの都合で型変数を持たされてしまった型を引数に取るのはなんかうざいのでちょっと逆転させます

type alias Model =
    { ham : Ham, egg : Egg }

type alias WithKey m =
    { m | key : Key }

view : Model -> Html Msg
view = ...

main : Program () (WithKey Model) Msg
main = ...

よしよしこれでProgramの都合はBrowser.applicationが直接依存する関数だけにとどまるぞ🎉

解決策3

Modelの詰め替えがつらい

WithKey Model -> Modelの処理は自動でやってくれないので中身を取り出して詰め替えしないだめです。Modelにフィールド増えたときも増やさないといけないです
まあめんどいです

とうことで今日仕事中に唐突に思いついたんですけどこれでどうでしょうか?

type WithKey m
    = WithKey Key m

これなら要素の詰め替えもしなくてよい

解決策2と比べて代わりにupdateの返り値を必ずWithKeyで包まなくてはならなくなったのですが、updateの内で対処するのは理にかなってるので今はこれでやってみてます

おわり

[feldmanがこの件に関して対処するようです]
(https://github.com/elm-explorations/test/issues/24#issuecomment-444143745)

Cmdのテストとかできるようになるんですかねー、たのしみー

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?