question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TypeScript types: oneOf() should narrow/constrain the type

See original GitHub issue

Describe the bug oneOf(..) constraint should constrain the type to the narrowed values, but it doesn’t.

To Reproduce I couldn’t make a repro with the codesandbox template because this is a TS-specific issue. However this snippet illustrates the issue:

// Works, but overlayed broad type.
const unconstrained: Yup.SchemaOf<string> = Yup.string()
    .required()
    .oneOf(["foo", "bar"]);

// COMPILER ERROR OUTPUT:
// Type 'RequiredStringSchema<string | undefined, Record<string, any>>' is not assignable to type 'BaseSchema<Maybe<"foo">, Record<string, any>, "foo"> | BaseSchema<Maybe<"bar">, Record<string, any>, "bar">'.
//   Type 'RequiredStringSchema<string | undefined, Record<string, any>>' is not assignable to type 'BaseSchema<Maybe<"bar">, Record<string, any>, "bar">'.
//     Types of property '__inputType' are incompatible.
//       Type 'string | undefined' is not assignable to type 'Maybe<"bar">'.
//     Type 'string' is not assignable to type 'Maybe<"bar">'.
const broken: Yup.SchemaOf<"foo" | "bar"> = Yup.string()
    .required()
    .oneOf(["foo", "bar"]);

Expected behavior Calling oneOf() should constrain the schema’s type so that the broken value (see example above) compiles. I’m also open to other ways of accomplishing this if I’m just “doing it wrong”.

The source (for master at the time of this issue) is part of BaseSchema: https://github.com/jquense/yup/blob/67c96ae7f8fcb59758732b2956ff0b7390f08213/src/schema.ts#L668-L697

…However, I don’t think there’s a way to constrain it on BaseSchema since it uses the polymorphic this return type, is there? I think you could override the method in StringSchema, etc to specify a stricter return type… kind of awkward, but it would be an improvement. Let me know your thoughts about a solution - I can make a PR implementing it if you’d like. I’ve made a few for you in the past so you know I’m good for it.

Platform (please complete the following information): Current version of Yup (0.32.8). Problem is also present in master as of now (https://github.com/jquense/yup/tree/67c96ae7f8fcb59758732b2956ff0b7390f08213).

Additional context Issue #1165 looks to be related, but there isn’t any mention of as const in the readme anymore so I’m guessing it’s out of date/not relevant anymore.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:2
  • Comments:15 (4 by maintainers)

github_iconTop GitHub Comments

21reactions
janKozie1commented, Feb 4, 2021

@ejose19 You should be able to do it with mixed<Type>(). Using it like .mixed<Enum>().oneOf(Object.values(Enum)) worked great for me so far

const schema: yup.SchemaOf<Foo> = yup.object({
  bar: yup.mixed<Opt>().required().oneOf(opts),
});
7reactions
lgenzeliscommented, Jul 15, 2021

Similar to what @janKozie1 wrote, you can simply write this as

const mySchema = yup.object().shape({
  name: yup.string().required(),
  type: yup.mixed<'foo' | 'bar'>().oneOf(['foo', 'bar']).required(),
});

The cool thing about it is that, if you were to add an option (baz) to the oneOf array, typescript would complain automatically:

const mySchema = yup.object().shape({
  name: yup.string().required(),
  type: yup.mixed<'foo' | 'bar'>().oneOf(['foo', 'bar', 'baz']).required(),
 // TS2322: Type '"baz"' is not assignable to type 'Reference  | Maybe"foo" | "bar" | undefined>'.
});
Read more comments on GitHub >

github_iconTop Results From Across the Web

Documentation - Advanced Types - TypeScript
This page lists some of the more advanced ways in which you can model types, it works in tandem with the Utility Types...
Read more >
Implement a generic oneOf type with Typescript
Have you ever came across a case in your Typescript codebase where you were trying to describe a oneOf ? I did multiple...
Read more >
Constraining type in Typescript generic to be one of several ...
The first is that TypeScript only recognizes two direct index signature types: [k: string] , and [k: number] . That's it. You can't...
Read more >
TypeScript: How to get types from arrays - Steve Holgado
The problem. It can be useful to get a type from an array of values so that you can use it as, say,...
Read more >
Mastering TypeScript mapped types - LogRocket Blog
It signals to the TypeScript compiler that the type of the underlying value could be any one of the types included in the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found