-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Different typing for SafeParseReturnType<T> #3266
Comments
As far as I see, the suggestion is exactly the opposite of TypeScript good practices - it incorrectly describes the return type and does not enable the standard practice of type narrowing based on eg Using literals as TypeScript types is a best practice - not sure where you are getting the nonsense of the opposite being the case from... You are just using TypeScript wrong. The correct expression to use in your screenshot is |
I think there's a middle path here, where we keep the safety of the current type (which is the main reason I use zod) but improve the ergonomics so that it can be used more flexibly. export declare type SafeParseSuccessOutput<Output> = {
success: true;
data: output;
error? : never
}
export declare type SafeParseError<Input> = {
success: false;
error: ZodError<Input>;
data? : never
} The never fields do not affect safety; this is still a tagged union that can be refined by checking |
Yes, that is a nice approach, it's a pattern used by other libraries as well, somehow forgot to write about it. It can be made slightly "better" by using a base type (not really relevant for this small type, but having two completely disjoint types breaks eg. the automatic field rename refactoring which is relevant for bigger types) eg. something like: type SafeParseBase = {
success: boolean;
data?: never;
error?: never;
}
export declare type SafeParseSuccessOutput<Output> = SafeParseBase & {
success: true;
data: output;
}
export declare type SafeParseError<Input> = SafeParseBase & {
success: false;
error: ZodError<Input>;
} Should probably actually use |
The type Zod implements is a disjoint union type. That's how disjoint union types are implemented. It's the only correct type in this situation. Proposed type has 8 possible values instead of 2, and is just wrong. Please consult TS documentation or any other literature on how to properly apply bad practices in your code. |
Again, not the only correct type; the version with |
As others have said, this is intended to be a discriminated union and it dramatically improves DX due to TypeScript's automatic type narrowing. |
@colinhacks the suggestion I made in the PR is still a discriminated union and in addition to the DX benefits of that also allows for better DX when the user needs to respond with something even if parsing failed. This is a fairly common case and even came up in the tests for safeParse. Does that seem like a reasonable change? |
Behavior description
Nowadays, the safeParse and safeParseAsync - functions for parsing Zod schemas - return types are based on SafeParseReturnType, this type is an union containing the following types:
SafeParseSuccess<Output>
SafeParseError<Input>
Behavior problem
This kind of behavior, besids applying bad practices by design - here I'm talking about having const values true and false for success instead of a boolean - also needs an explicit declaration on what type it should be. This situation causes more complexity in the user code - complexity that should be handled by the library itself and it's against the TypeScript idea of good inference and usability.
Solution suggestion
My solution, for that case, would be implementing a single typing for SafeParseReturnType without unions - in a way that will not break existing code and will correctly adapt to any situation that the previously implemented unions covered.
Code:
The text was updated successfully, but these errors were encountered: