gcanti / io-ts-types

A collection of codecs and combinators for use with io-ts
https://gcanti.github.io/io-ts-types/
MIT License
311 stars 40 forks source link

t.stringFromRegex #131

Closed waynevanson closed 3 years ago

waynevanson commented 4 years ago

🚀 Feature request

Current Behavior

Feature does not exist.

Desired Behavior

User to use a RegExp to assert a string.

Suggested Solution

First time I've written one of these. Not tested.

import * as t from "io-ts";
import { pipe } from "fp-ts/lib/pipeable";
import { option as O, either as E } from "fp-ts";

const guardStringFromRegex = (regex: RegExp) => (a: unknown): a is string =>
  pipe(
    a,
    O.fromPredicate(t.string.is),
    O.map((a) => a.match(regex)),
    O.chain(O.fromNullable),
    O.isSome
  );

const stringFromRegex = (regexp: RegExp, name: string = "stringFromRegexp") => {
  const refinement = guardStringFromRegex(regexp);
  return new t.Type(
    name,
    refinement,
    (u, c) => (!refinement(u) ? t.failure(u, c) : t.success(u)),
    (a) => a
  );
};

Who does this impact? Who is this for?

All users

Describe alternatives you've considered

No alternatives. Tried looking around but didn't see anything.

Additional context

Your environment

Software Version(s)
fp-ts ^2.6.6
io-ts ^2.2.6
io-ts-types ^0.3.4
TypeScript ^3.9.5
mlegenhausen commented 4 years ago

This looks a lot like what fromRefinement is doing. You would use it like this

fromRefinement('MyRegExpType', (u): u is string => t.string.is(u) && /test/.test(u))

Or what I would recommend when you have strings that follow a certain structure is to use a branded type

waynevanson commented 4 years ago

@mlegenhausen That does look similar. I feel like the DX of the suggested solution for RegExp's are a better.

I didn't get that far in the documentation, so thank you for the references.

EricCrosson commented 3 years ago

May we close this issue @waynevanson ?