Last active
March 21, 2021 21:14
-
-
Save alarbada/8180e2784223d49166723a14c3f31397 to your computer and use it in GitHub Desktop.
Typescript nominal types with classes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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