Skip to content

Commit

Permalink
fix: handle undefined as optional during validation phase (#240)
Browse files Browse the repository at this point in the history
  • Loading branch information
tvillaren authored May 13, 2024
1 parent 16b5ce6 commit 899c5ab
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 1 deletion.
100 changes: 100 additions & 0 deletions src/core/validateGeneratedTypes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,106 @@ describe("validateGeneratedTypes", () => {
expect(errors).toEqual([]);
});

it("should return no error if we use a non-optional undefined", () => {
const sourceTypes = {
sourceText: `
export interface Citizen {
villain: undefined;
};
`,
relativePath: "source.ts",
};

const zodSchemas = {
sourceText: `// Generated by ts-to-zod
import { z } from "zod";
export const citizenSchema = z.object({
villain: z.undefined()
});
`,
relativePath: "source.zod.ts",
};

const integrationTests = {
sourceText: `// Generated by ts-to-zod
import { z } from "zod";
import * as spec from "./${sourceTypes.relativePath.slice(0, -3)}";
import * as generated from "./${zodSchemas.relativePath.slice(0, -3)}";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function expectType<T>(_: T) {
/* noop */
}
export type CitizenInferredType = z.infer<typeof generated.citizenSchema>;
expectType<CitizenInferredType>({} as spec.Citizen);
expectType<spec.Citizen>({} as CitizenInferredType);
`,
relativePath: "source.integration.ts",
};

const errors = validateGeneratedTypes({
sourceTypes,
zodSchemas,
integrationTests,
skipParseJSDoc: false,
});

expect(errors).toEqual([]);
});

it("should return no error if we use a non-optional undefined in union type", () => {
const sourceTypes = {
sourceText: `
export interface Citizen {
villain: string | undefined;
};
`,
relativePath: "source.ts",
};

const zodSchemas = {
sourceText: `// Generated by ts-to-zod
import { z } from "zod";
export const citizenSchema = z.object({
villain: z.union([z.string(), z.undefined()])
});
`,
relativePath: "source.zod.ts",
};

const integrationTests = {
sourceText: `// Generated by ts-to-zod
import { z } from "zod";
import * as spec from "./${sourceTypes.relativePath.slice(0, -3)}";
import * as generated from "./${zodSchemas.relativePath.slice(0, -3)}";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function expectType<T>(_: T) {
/* noop */
}
export type CitizenInferredType = z.infer<typeof generated.citizenSchema>;
expectType<CitizenInferredType>({} as spec.Citizen);
expectType<spec.Citizen>({} as CitizenInferredType);
`,
relativePath: "source.integration.ts",
};

const errors = validateGeneratedTypes({
sourceTypes,
zodSchemas,
integrationTests,
skipParseJSDoc: false,
});

expect(errors).toEqual([]);
});

it("should return an error if the types doesn't match", () => {
const sourceTypes = {
sourceText: `
Expand Down
7 changes: 6 additions & 1 deletion src/utils/fixOptionalAny.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import ts, { factory as f } from "typescript";

/**
* Add optional property to `any` or imported types to workaround comparison issue.
* Add optional property to `any`, `undefined` or imported types to workaround comparison issue.
*
* ref:
* -> https://github.com/fabien0102/ts-to-zod/issues/140
* -> https://github.com/fabien0102/ts-to-zod/issues/203
* -> https://github.com/fabien0102/ts-to-zod/issues/239
*
*/
export function fixOptionalAny(
Expand All @@ -14,8 +15,12 @@ export function fixOptionalAny(
) {
function shouldAddQuestionToken(node: ts.TypeNode) {
return (
// https://github.com/fabien0102/ts-to-zod/issues/140
node.kind === ts.SyntaxKind.AnyKeyword ||
// https://github.com/fabien0102/ts-to-zod/issues/239
node.kind === ts.SyntaxKind.UndefinedKeyword ||
// Handling type referencing imported types
// https://github.com/fabien0102/ts-to-zod/issues/203
(ts.isTypeReferenceNode(node) &&
importsToHandleAsAny.has(node.typeName.getText(sourceFile)))
);
Expand Down

0 comments on commit 899c5ab

Please sign in to comment.