Skip to content

Instantly share code, notes, and snippets.

@alarbada
Last active March 21, 2021 21:14
Show Gist options
  • Save alarbada/8180e2784223d49166723a14c3f31397 to your computer and use it in GitHub Desktop.
Save alarbada/8180e2784223d49166723a14c3f31397 to your computer and use it in GitHub Desktop.
Typescript nominal types with classes
import * as D from 'io-ts/Decoder'
import * as fp from 'fp-ts/function'
// Nominal types without much ceremony: "class" types
// AKA I want to convert typescript types into fsharp types while using
// typescript
// Not much syntax needed, so they are easy to create. That's what Fable uses to
// construct their own records and DUs.
class UserId {
constructor(public value: string, private _?: string) {}
}
class SellerId {
constructor(public value: string, private _?: string) {}
}
const u1 = new UserId('1234')
const s1: UserId = new SellerId('1234') // Error, not assignable because of the private '_' property
namespace A {
export class UserId {
constructor(public value: string, private _?: string) {}
}
}
namespace B {
export class UserId {
constructor(public value: string, private _?: string) {}
}
}
const u2 = new A.UserId('1234')
const u3: A.UserId = new B.UserId('1234') // Two different UserIds in two domains are distinct and not assignable
// Let's say you want to use these types with some validation library.
// Io ts let's you do just that
function createDecoder<NominalClassType extends { val: unknown }>(
baseType: D.Decoder<unknown, NominalClassType['val']>,
classType: new (value: NominalClassType['val']) => NominalClassType
) {
return fp.pipe(
baseType,
D.parse((id) => D.success(new classType(id)))
)
}
const sellerIdDecoder = createDecoder(D.string, SellerId)
const SellerIdDecoder = D.struct({
seller_id: sellerIdDecoder,
})
const unparsedString1 = `
{ "seller_id": "1234623" }
`
const unparsedString2 = `
{ "seller_d": "1234623" }
`
const unparsedString3 = `
{ "seller_ "1234623" }
`
const decoded = SellerIdDecoder.decode(JSON.parse(unparsedString1))
const decoded2 = SellerIdDecoder.decode(unparsedString2)
const decoded3 = SellerIdDecoder.decode(unparsedString3)
// Then, pattern match your decoded things.
console.log(decoded)
console.log(decoded2)
console.log(decoded3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment