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

Add case insensitivity for string type literals #134

Open
piersmacdonald opened this issue Jul 26, 2018 · 10 comments
Open

Add case insensitivity for string type literals #134

piersmacdonald opened this issue Jul 26, 2018 · 10 comments

Comments

@piersmacdonald
Copy link

it's helpful to define an in put as being t.keyof({ firstName: null, preferredName: null }); but it would be nice if they could send firstName, firstname, fIrStNaMe`

@sledorze
Copy link
Collaborator

@piersmacdonald we strive keeping io-ts mininal and lean. Io-ts-types repo is where such additional Types may be defined.

@piersmacdonald
Copy link
Author

Fair enough, thanks for the quick response.

@kpritam
Copy link

kpritam commented Jul 15, 2020

@piersmacdonald Did you come up with this type? I couldn't find it in io-ts-types.

@gcanti is there easy way to achieve this with current Decoder?

One way to do this is to have all literals in lowercase and then convert incoming string to lowercase and then forward it to D.literals decoder

But this forces me to define all literal types in lowercase.

 const lowerCase = pipe(
    D.string,
    D.map((s) => s.toLowerCase())
  )

  const ComponentType = pipe(lowerCase, D.compose(D.literal('hcd', 'assembly')))
  type ComponentType = D.TypeOf<typeof ComponentType>

  console.log(ComponentType.decode('HCD'))

@gcanti
Copy link
Owner

gcanti commented Jul 15, 2020

@kpritam I would return the original input

import * as E from 'fp-ts/lib/Either'
import { flow } from 'fp-ts/lib/function'
import * as D from 'io-ts/lib/Decoder'

const decoder: D.Decoder<unknown, string> = {
  decode: flow(
    D.string.decode,
    E.chainFirst((s) => D.literal('hcd', 'assembly').decode(s.toLowerCase()))
  )
}

console.log(decoder.decode('HCD'))
// => { _tag: 'Right', right: 'HCD' }

@kpritam
Copy link

kpritam commented Jul 15, 2020

@gcanti but this forces to define all the literals in lowercase, that might not what you always want.

Basically is it possible to make decoding of following literals case insensitive?

const compType = D.literal('Hcd', 'Assembly')

// all the following cases should pass and all should return **Hcd**
compType.decode('hcd')
compType.decode('Hcd')
compType.decode('HCD')

@gcanti
Copy link
Owner

gcanti commented Jul 15, 2020

all the following cases should pass and all should return Hcd

Ah ok, I misinterpreted the requirements, I thought you always wanted the original input back

@gcanti
Copy link
Owner

gcanti commented Jul 15, 2020

import * as E from 'fp-ts/lib/Either'
import { flow, pipe } from 'fp-ts/lib/function'
import * as O from 'fp-ts/lib/Option'
import * as A from 'fp-ts/lib/ReadonlyArray'
import * as D from 'io-ts/lib/Decoder'

export const iliteral = <A extends readonly [string, ...Array<string>]>(
  ...values: A
): D.Decoder<unknown, A[number]> => {
  const message = values.map((value) => JSON.stringify(value)).join(' | ')
  return {
    decode: flow(
      D.string.decode,
      E.chain((s) =>
        pipe(
          values,
          A.findIndex((value) => value.toLowerCase() === s.toLowerCase()),
          O.fold(
            () => D.failure(s, message),
            (i) => D.success(values[i])
          )
        )
      )
    )
  }
}

@kpritam
Copy link

kpritam commented Jul 15, 2020

@gcanti great, thanks.

Does it make sense for this to go into main library or io-ts-types?

It is pretty common use case that these literal types are defined as case insensitive enums in other languages and then its upto codec library to decide how to encode/decode them.

@piersmacdonald
Copy link
Author

@kpritam ended up switching libraries for the job. This question was asked in the context of validating user requests for a REST service. So I switched to class-validator which is more specific to my use case. Still make some use of io-ts but not in that context.

@gcanti
Copy link
Owner

gcanti commented Jul 16, 2020

Does it make sense for this to go into main library or io-ts-types?

👍 once Decoder becomes official, moving to io-ts-types as a reminder

@gcanti gcanti reopened this Jul 16, 2020
@gcanti gcanti transferred this issue from gcanti/io-ts Jul 16, 2020
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

4 participants