> For the complete documentation index, see [llms.txt](https://orasund.gitbook.io/elm-cookbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://orasund.gitbook.io/elm-cookbook/recipes-1/making-impossible-states-impossible/write-safer-functions-using-phantom-types.md).

# Write safer functions using Phantom Types

{% tabs %}
{% tab title="Problem" %}

```
type alias LoginForm =
    { username : String
    , password : String
    , isValid : Bool
    }

{-| Creates a User

Only use this function if the LoginForm was validated.
-}
createUser : LoginForm -> User
createUser loginForm =
    if loginForm.isValid then
        User.create loginForm.username
    else
        Debug.todo "This should not happen."
```

{% endtab %}

{% tab title="Solution" %}

```
type LoginForm valid =
    LoginForm
        { username : String
        , password : String
        }

type Valid = Valid

{-| Creates a User
-}
createUser : LoginForm Valid -> User
createUser (LoginForm loginForm) =
        User.create loginForm.username
        
validate : LoginForm () -> LoginForm Valid
validate =
    ...
```

{% endtab %}
{% endtabs %}

## Question

How can I  ensure that a user can only be created with a valid login form?

## Answer

Use a so called Phantom Type:

```
type LoginForm valid = --valid is not used in the definition
    LoginForm
        { username : String
        , password : String
        }
        
type Valid = Valid
```

Use `LoginForm ()` for unvalidated forms and `LoginForm Valid` for validated ones.

## Further reading

* 📄**Article:** [Advanced Types in Elm - Phantom Types](https://medium.com/@ckoster22/advanced-types-in-elm-phantom-types-808044c5946d) by Charlie Koster
