elm-review-ports
rule for NoUnusedPorts
elm-ts-interop
helps avoid this by using a single port-pair (interopToElm and interopFromElm).TypeScript Literal Types are useful for describing the shape of JSON. Since JSON doesn't have custom types or enums, literals greatly expand the expressive power of JSON.
Since Elm ports and flags are limited to JSON, elm-ts-interop
relies heavily on the guarantees from TypeScript Literal Types.
An example of a Literal Type is a literal string. With this elm-ts-json
Encoder:
encoder : Encoder Kind
encoder =
TsEncode.literal (Json.Encode.string "hello!")
We get a TypeScript type "hello!"
. Notice that it is a type, not just a value.
ellie-app fQWYRPSQxvsa1
Encodes into a TypeScript Union type. In TypeScript, Union types are "untagged unions". Elm's Custom Types are "tagged unions."
That means we can do
type IdStringOrNumber = IdString String | IdNumber Int
id : IdStringOrNumber
id = IdString "abc123"
type Id = string | number;
id: Id = "abc123";
Similar pattern to miniBill/elm-codec
, the first argument is a function which has 1 argument for each variant encoder and 1 argument which is the value that we can do a case expression on.
In the case expression, we pick an encoder to use. The variant encoder parameters correspond to the pipeline below.
encoder : Encoder Kind
encoder =
TsEncode.union
(\vError vWarning vInfo vAlert value ->
case value of
Error ->
vError
Warning ->
vWarning
Info ->
vInfo
Alert ->
vAlert
)
|> TsEncode.variantLiteral (Json.Encode.string "error")
|> TsEncode.variantLiteral (Json.Encode.string "warn")
|> TsEncode.variantLiteral (Json.Encode.string "info")
|> TsEncode.variantLiteral (Json.Encode.string "alert")
|> TsEncode.buildUnion
The TypeScript compiler uses control flow analysis to narrow types. So if you check the type of a value in a conditional, the TypeScript compiler is aware of the type information within the conditional branches.
// logKind's type is 'error' | 'warning' | 'info' | 'alert'
if (fromElm.data.logKind === "alert") {
// logKind's type is 'alert'
} else {
// logKind's type is 'error' | 'warning' | 'info'
}
TypeScript's Discriminated Union functionality uses Type Narrowing to get functionality like Elm's case expressions for Custom Types.
Serialization for an Encoder, Deserialization for a Decoder. Allows us to decouple type information. The types don't have to match in Elm and TypeScript. But we can safely change our Encoders and Decoders because the type information will always be in sync with elm-ts-interop
.