ianstormtaylor / superstruct

A simple and composable way to validate data in JavaScript (and TypeScript).
https://docs.superstructjs.org
MIT License
6.95k stars 224 forks source link

`Describe` incorrectly handles single literal types. #1240

Open yeoffrey opened 2 months ago

yeoffrey commented 2 months ago

Description

It seems that using a single literal in an enums struct will not be interpreted by Describe properly when working with TS types that are literals. Is this the wrong usage of enums or describe? If not, I'm willing to submit a PR for this.

Reproduce

Here is a type which is a union of string literals (working).

import {Describe, enums} from 'superstruct';

type MyType = 'foo' | 'bar';

const MyTypeStruct: Describe<MyType> = enums(['foo', 'bar']);

However, when using Describe with a type which is a single string literal, there is an error.

import {Describe, enums} from 'superstruct';

type MyType = 'foo';

const MyTypeStruct: Describe<MyType> = enums(['foo']);

Error:

Type 'Struct<"foo", { foo: "foo"; }>' is not assignable to type 'Describe<"foo">'.
     Type '{ foo: "foo"; }' is not assignable to type '"foo"'. [2322]

Using Infer

This seems to work the other way when using Infer from a struct to generate a type. For example:

import {Infer, enums} from 'superstruct';

const literalEnum = enums(['foo']);

type MyType = Infer<typeof literalEnum>;

const MyLiteral: MyType = 'foo';

Extra info:

Node: v20.14.0 SuperStruct: v1.0.4 I have strict enabled in my TypeScript configuration for these examples. I'm willing to submit a PR for this.

yeoffrey commented 2 months ago

For now, just use literal(). Maybe there should be a suggestion if you create an enums with only one value. Intuitively this to me feels like something that could be streamlined a bit. Is enums just an array of literals?