Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Branded types with experimental Decoder module #608

Closed
florianbepunkt opened this issue Sep 21, 2021 · 1 comment
Closed

Branded types with experimental Decoder module #608

florianbepunkt opened this issue Sep 21, 2021 · 1 comment

Comments

@florianbepunkt
Copy link

📖 Documentation

I read through #453 but haven't found an answer to the following questions regarding branded types or what the recommendation is for handling branded types. It reads to use refine or parse but I haven't understood how.

Branded primitives

Consider a string that matches a regex pattern should be branded. Is the following correct? It does work but I wonder if there is a recommended / better approach

import * as COD from "io-ts/Codec";
import * as DEC from "io-ts/Decoder";
import * as ENC from "io-ts/Encoder";
import * as E from "fp-ts/Either"

const fromPredicate =
  <A>(predicate: (i: unknown) => i is A, message: string) =>
  (i: unknown) =>
    E.fromPredicate(predicate, () => DEC.error(i, message))(i);

interface DocumentCodeBrand { readonly DocumentCode: unique symbol; }
type DocumentCode = string & DocumentCodeBrand;

const PATTERN = /^[A-Z]\d[A-Z]\d$/;
const is = (i: unknown): i is DocumentCode => typeof i === "string" && PATTERN.test(i);
const Encoder: ENC.Encoder<string, DocumentCode> = { encode: String };
const Decoder: DEC.Decoder<unknown, DocumentCode> = {
  decode: CAT.fromPredicate(is, `DocumentCode must be a string of format ${String(PATTERN)}`),
};
const Codec: COD.Codec<unknown, string, DocumentCode> = COD.make(Decoder, Encoder);

Branded structures

Consider this codec and the corresponding type. How can you achieve a branded struct?

const StructCodec = COD.struct({
  documentCode: Codec,
  someValue: COD.string,
})

type Struct = COD.TypeOf<typeof StructCodec>;
@tchak
Copy link

tchak commented Oct 17, 2021

I think this is correct. It is pretty much how it is implemented in this experimental branch gcanti/io-ts-types#127. You can use Guard to reduce code a bit (look at the implementation of UUID for example). I published some of the code in this branch as https://github.com/tchak/io-ts-types-experimental (npm install io-ts-types-experimental).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants