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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Struct type with literals not inferred correctly in Decoder #656

Closed
vecerek opened this issue Aug 27, 2022 · 2 comments
Closed

Struct type with literals not inferred correctly in Decoder #656

vecerek opened this issue Aug 27, 2022 · 2 comments

Comments

@vecerek
Copy link
Sponsor

vecerek commented Aug 27, 2022

馃悰 Bug report

Current Behavior

import * as D from "io-ts/Decoder";

/*
  Inferred as:
  Decoder<unknown, { _tag: string }>
 */
const incorrect = D.struct({
  _tag: D.literal("Some")
});

Expected behavior

I expect the type to be inferred as:

type A = Decoder<unknown, { _tag: "Some" }>;

Reproducible example

import * as D from "io-ts/Decoder";

const incorrect = D.struct({
  _tag: D.literal("Some")
});

Suggested solution(s)

I tried changing struct in the Decoder to:

export const struct = <A extends Record<string, Decoder<unknown, any>>>(
  properties: A
): Decoder<unknown, { [K in keyof A]: TypeOf<A[K]> }> => pipe(UnknownRecord as any, compose(fromStruct(properties)))

to better align with the implementation of struct in Codec, where this inference issue does not happen.

However, the type is then inferred as:

type A = Decoder<unknown, { _tag: unknown }>;

I suspect the implementation of TypeOf to be at fault there but I am not familiar with the theory behind Kleisli types, so it's become difficult for me to debug any further.

Additional context

I stumbled upon this after upgrading to TypeScript 4.8 where it caused build errors. My workaround to this issue was to cast the string to a const:

const correct = D.struct({
  _tag: D.literal("Some" as const)
});

Your environment

Which versions of io-ts are affected by this issue? Did this work in previous versions of io-ts?

This issue should be reproducible on the master branch. I don't know if the inference ever worked.

Software Version(s)
io-ts master
fp-ts 2.9.5 (the one used on master at the time of reporting the issue)
TypeScript 4.6.2 (the one used on master at the time of reporting the issue)
@gcanti
Copy link
Owner

gcanti commented Aug 27, 2022

@vecerek thanks for the bug report, I'm investigating. Looks like literal doesn't work as expected inside a struct with typescript@4.8 (while it works with typescript@4.7 and earlier versions)

@gcanti
Copy link
Owner

gcanti commented Aug 28, 2022

Looks like changing the literal signature from

export const literal: <A extends readonly [S.Literal, ...ReadonlyArray<S.Literal>]>(
  ...values: A
) => Decoder<unknown, A[number]>

to

export const literal: <A extends readonly [L, ...ReadonlyArray<L>], L extends S.Literal = S.Literal>(
  ...values: A
) => Decoder<unknown, A[number]>

solves the issue, PR here #657

@gcanti gcanti closed this as completed in 9e8ef0e Aug 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants