superstruct icon indicating copy to clipboard operation
superstruct copied to clipboard

enums gives relaxed type

Open Louis-Tian opened this issue 3 years ago • 3 comments

const struct = object({text: enums(["foo", "bar"])})
const {text}  = create({ text: "foo"}, struct)

the text variable is given a type of string while I am expecting "foo" | "bar". I can get around the problem with the more verbose union([literal("foo"), literal("bar")])

Louis-Tian avatar Mar 04 '22 05:03 Louis-Tian

bumped into this problem. I used zod before superstruct and it works beautifully in zod.

capaj avatar Mar 28 '22 16:03 capaj

@Louis-Tian hmm, not sure why that's happening. Based on tests here: https://github.com/ianstormtaylor/superstruct/blob/main/test/typings/enums.ts it looks like the behavior you expect, for example:

test<'a' | 'b' | 'c'>((x) => {
  assert(x, enums(['a', 'b', 'c']))
  return x
})

ianstormtaylor avatar Jun 02 '22 13:06 ianstormtaylor

It seems like this is only happening when enums is used inside an object.

paescuj avatar Jun 13 '22 08:06 paescuj

Enums inside objects are not being used in the assert function. There is a way to coerse the enum type?

`const schema = object({ something: enums(['string1', 'string2']), });

export type IUser = Infer;

const validateUser = (any: unknown) => { assert(any, schema); return any; };`

In the example above the assert is returning the field 'something' as just string, not 'string1' | 'string2' as should.

For now I'm doing that way:

const validateUser = (any: unknown) => { assert(any, schema); return { ...any, type: any.type === 'string1 ? 'string1' : 'string2', }; }

alicercedigital avatar Aug 15 '22 01:08 alicercedigital

@ianstormtaylor Sorry for the late reply. @paescuj is right, this happens when you wrap the enums inside an object. Please find the screenshot below. image

Louis-Tian avatar Aug 17 '22 04:08 Louis-Tian

@alicercedigital replace your enums with union([literal("string1"), literal("string2")]) should get around the problem.

Louis-Tian avatar Aug 17 '22 04:08 Louis-Tian

Fixed and released in 0.16.3! The generic type needed a little tweaking to preserve the more specific types instead of being expanded to string.

ianstormtaylor avatar Sep 20 '22 13:09 ianstormtaylor

For anyone else getting compile errors due to 0.16.3, I needed to drop the as const from type({text: enums(["foo", "bar"] as const)}) as a result of this change.

(Unfortunately I use that pattern everywhere so all my projects are broken by 0.16.3 😅)

birtles avatar Sep 21 '22 00:09 birtles

@birtles shoot, I'm really sorry about that. I've just released 0.16.4 which should fix the issue (has to do with readonly arrays). And I've added a test to catch those in the future. Thanks for reporting it.

ianstormtaylor avatar Sep 21 '22 03:09 ianstormtaylor

Thanks so much!

birtles avatar Sep 21 '22 04:09 birtles