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.

Demand for VSCode Extension?

See original GitHub issue

Was playing around with VSCode and Zod based on #53 – seeing if there is enough demand for this to put time into the concept. It is slow in the preview as I built that out in about 1 hour, but seems it could be nice - and make it easier to use Zod since you wouldn’t really need to even learn all the specifics - you could just create your TypeScript Type then translate it.

It utilizes the TypeScript Compiler API to read the AST and infer from there.

Since this is just using the TypeScript compiler API - this could pretty easily become a browser tool as well which you could just paste in your type and get a valid zod schema out from it.

On that note, this is more of a Typescript Plugin than a VSCode Extension - since the vscode part of it is just providing the menu option to run the TS Compiler and it uses the TS Compiler to build Typescript Code.

export const generatePrimitive = ({ kind, name, props, zodImportValue }: {
  kind: ts.SyntaxKind;
  name: string;
  zodImportValue: string;
  props: { isOptional: boolean; errorMessage: undefined | string; isNullable?: boolean }
}) => {
  let flags = '';

  if (props.isOptional) {
    flags += '.optional()';
  }
  if (props.isNullable) {
    flags += '.nullable()';
  }

  let errorMessage = props.errorMessage ? wrapQuotes(props.errorMessage) : '';

  switch (kind) {
    case ts.SyntaxKind.NumericLiteral:
      return `${zodImportValue}.literal(${name})${flags}`;
    case ts.SyntaxKind.StringLiteral:
      return `${zodImportValue}.literal(${wrapQuotes(name)})${flags}`;
    case ts.SyntaxKind.StringKeyword:
      return `${zodImportValue}.string()${flags}`;
    case ts.SyntaxKind.BooleanKeyword:
      return `${zodImportValue}.boolean()${flags}`;
    case ts.SyntaxKind.NullKeyword:
      return `${zodImportValue}.null()${flags}`;
    case ts.SyntaxKind.UndefinedKeyword:
      return `${zodImportValue}.undefined()${flags}`;
    case ts.SyntaxKind.NumberKeyword:
      return `${zodImportValue}.number()${flags}`;
    case ts.SyntaxKind.AnyKeyword: 
      return `${zodImportValue}.any()${flags}`;
    case ts.SyntaxKind.BigIntKeyword:
      return `${zodImportValue}.bigint()${flags}`;
    case ts.SyntaxKind.VoidKeyword:
      return `${zodImportValue}.void()${flags}`;
    case ts.SyntaxKind.ClassKeyword: {
      if (name === 'Date') {
        return `${zodImportValue}.date()${flags}`;
      }
      // TODO : Handle Class & InstanceOf based on symbol & import detection context
    }
    default:
     return `${zodImportValue}.any(${errorMessage})`;
  }
};


The code above just uses strings to build it which was easier in this case. For those potentially interested, to move to using the TypeScript Compiler / AST to build it all, the generated type in the gif would be something like:

[
  ts.createVariableStatement(
    undefined,
    ts.createVariableDeclarationList(
      [ts.createVariableDeclaration(
        ts.createIdentifier("TestSchema"),
        undefined,
        ts.createCall(
          ts.createPropertyAccess(
            ts.createIdentifier("z"),
            ts.createIdentifier("object")
          ),
          undefined,
          [ts.createObjectLiteral(
            [
              ts.createPropertyAssignment(
                ts.createIdentifier("three"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createCall(
                      ts.createPropertyAccess(
                        ts.createIdentifier("z"),
                        ts.createIdentifier("literal")
                      ),
                      undefined,
                      [ts.createStringLiteral("hi")]
                    ),
                    ts.createIdentifier("optional")
                  ),
                  undefined,
                  []
                )
              ),
              ts.createPropertyAssignment(
                ts.createIdentifier("one"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createIdentifier("z"),
                    ts.createIdentifier("number")
                  ),
                  undefined,
                  []
                )
              ),
              ts.createPropertyAssignment(
                ts.createIdentifier("two"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createIdentifier("z"),
                    ts.createIdentifier("literal")
                  ),
                  undefined,
                  [ts.createNumericLiteral("3")]
                )
              ),
              ts.createPropertyAssignment(
                ts.createIdentifier("four"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createIdentifier("z"),
                    ts.createIdentifier("string")
                  ),
                  undefined,
                  []
                )
              ),
              ts.createPropertyAssignment(
                ts.createIdentifier("five"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createIdentifier("z"),
                    ts.createIdentifier("date")
                  ),
                  undefined,
                  []
                )
              )
            ],
            true
          )]
        )
      )],
      ts.NodeFlags.Const
    )
  ),
  ts.createTypeAliasDeclaration(
    undefined,
    undefined,
    ts.createIdentifier("Test"),
    undefined,
    ts.createTypeReferenceNode(
      ts.createQualifiedName(
        ts.createIdentifier("z"),
        ts.createIdentifier("infer")
      ),
      [ts.createTypeQueryNode(ts.createIdentifier("TestSchema"))]
    )
  )
];

–>

const TestSchema = z.object({
	three: z.literal('hi').optional(),
	one: z.number(),
	two: z.literal(3),
	four: z.string(),
	five: z.date()
})

type Test = z.infer<typeof TestSchema>;

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:34
  • Comments:11 (3 by maintainers)

github_iconTop GitHub Comments

6reactions
bradennapiercommented, Aug 3, 2020

https://github.com/bradennapier/zod-web-converter

Here it is running in web browser by just modifying the ts-ast-viewer source to include the conversion command. Could be a powerful tool to host where people could just open it and paste in their types and get the values they need out from that.

Could pretty easily also convert graphql as requested to be a pretty awesome all-encompassing tool.

You can build and play for yourself pretty easily just follow the start instructions. This is compiling a bunch of versions of typescript you can choose so it takes a bit to compile but that isn’t really needed.

Screen Shot 2020-08-03 at 4 15 20 AM Screen Shot 2020-08-03 at 4 16 54 AM

😛

4reactions
fabien0102commented, Mar 30, 2021

@bradennapier I think I have a nice base for this kind of vscode extension, I tried to cover everything with unit tests & avoid any typecasting/any to be able to throw an explicit error when typescript can’t be translated into a zod schema. I also did find a nice trick for the “confidence” problem, I do generate an integration tests that compare z.infer and the original types (https://github.com/fabien0102/ts-to-zod/blob/main/example/heros.integration.ts).

I still need to think a bit how, but I guess we should be able to bake this integration test part inside the generation process 🤔

The project -> https://github.com/fabien0102/ts-to-zod

Since this issue seams to be quite popular, I will probably try to make a VSCode extension with this new library as core 😃 (I must admit that this is a really fun project 😁)

Thanks again for your little POC 💯

Read more comments on GitHub >

github_iconTop Results From Across the Web

Extension Manifest - Visual Studio Code
At the core of Visual Studio Code's extensibility model is an extension (plug-in) manifest file where your extension declares its extension type(s), ...
Read more >
Managing Extensions in Visual Studio Code
VS Code extensions let you add languages, debuggers, and tools to your installation to support your development workflow. VS Code's rich extensibility model ......
Read more >
Extension API - Visual Studio Code
Visual Studio Code has a rich extension API. Learn how to create your own extensions for VS Code.
Read more >
Your First Extension - Visual Studio Code
Create your first Visual Studio Code extension (plug-in) with a simple Hello World example.
Read more >
Web Extensions - Visual Studio Code
Learn how to run extensions in Visual Studio Code for the web and the web extension host.
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