Hey, thanks for the library, I recently updated to "yup": "^0.32.1"
I'm getting some typescript errors when using enums as follows:
(FYI, I have uninstalled the @types/yup but no difference)
enum Currency {
GBP = "GBP",
USD = "USD",
}
type Form = {
currency: Currency;
};
export const formSchema: SchemaOf<Form> = object({
currency: string().oneOf(Object.values(Currency)).defined(),
}).defined();
This gives the, rather long-winded error of:
Type 'DefinedObjectSchema<{ currency: DefinedStringSchema<string | undefined, Record<string, any>>; }, Record<string, any>, TypeOfShape<{ currency: DefinedStringSchema<string | undefined, Record<...>>; }>>' is not assignable to type 'ObjectSchema<{ currency: BaseSchema<Maybe<Currency.GBP>, Record<string, any>, Currency.GBP> | BaseSchema<Maybe<Currency.USD>, Record<string, any>, Currency.USD>; }, Record<...>, TypeOfShape<...>, AssertsShape<...>>'.
The types of 'fields.currency' are incompatible between these types.
Type 'DefinedStringSchema<string | undefined, Record<string, any>>' is not assignable to type 'BaseSchema<Maybe<Currency.GBP>, Record<string, any>, Currency.GBP> | BaseSchema<Maybe<Currency.USD>, Record<string, any>, Currency.USD>'.
Type 'DefinedStringSchema<string | undefined, Record<string, any>>' is not assignable to type 'BaseSchema<Maybe<Currency.USD>, Record<string, any>, Currency.USD>'.
Types of property '__inputType' are incompatible.
Type 'string | undefined' is not assignable to type 'Maybe<Currency.USD>'.
Type 'string' is not assignable to type 'Maybe<Currency.USD>'.ts(2322)
FYI, declaring currency as a string is okay:
enum Currency {
GBP = "GBP",
USD = "USD",
}
type Form = {
currency: string;
};
export const formSchema: SchemaOf<Form> = object({
currency: string().oneOf(Object.values(Currency)).defined(),
}).defined();
I tried downgrading to "yup": "^0.31.1" with "@types/yup": "^0.29.10" and it was fine again.
0.32.0 has new very different types. I can't reproduce this tho, I'm guessing your actual case looks more like:
type Form = {
currency: Currency;
};
This would be expected unfortunately, oneOf doesn't currently narrow the schema type so you end up trying to cast a string to the narrower Currency. This may change in the future for now tho it isn't possible
This feels like a regression, we use to get the narrower type inference for free. Is it possible to restore the old behavior here?
EDIT: to clarify, using the enum feature of typescript and then using only enum entries in the oneOf list would allow the inferred type to be the enum type. This is what I have observed to be missing.
PRs welcome. I'm not against the behavior it's just not as straight forward as "do what the other types did" and I've not had a chance to look into it.
I guess the ideal would be able to do:
enum Currency {
GBP = "GBP",
USD = "USD",
}
type Form = {
currency: Currency;
};
export const formSchema: SchemaOf<Form> = object({
currency: string().oneOf(Currency).defined(),
}).defined();
I'll try to take a look at the code - maybe, if the typing is complex to cover all use cases, we could define a new method like oneOfEnum?
@jquense this behaviour is crucial for me so I'll be looking into fixing it and properly narrowing types for oneOf today. I hope you're open to accepting a PR :)
BTW, in the pre-TS yup version, definitely-typed types correctly returned the right alternative type after oneOf(). I think it's a feature which was lost with TS rewrite.
I think overriding oneOf() in StringSchema class and returning the modified typed StringSchema (or DefinedStringSchema or RequiredStringSchema - depending on where it's overridden) instance would do the trick. Because this stuff is mostly used for enums. (NumberSchema may may also be subject to this since enum can be number-based.)
Most helpful comment
I guess the ideal would be able to do:
I'll try to take a look at the code - maybe, if the typing is complex to cover all use cases, we could define a new method like
oneOfEnum?