Gathering detailed insights and metrics for zod-to-ts
Gathering detailed insights and metrics for zod-to-ts
Gathering detailed insights and metrics for zod-to-ts
Gathering detailed insights and metrics for zod-to-ts
npm install zod-to-ts
93.8
Supply Chain
100
Quality
75.7
Maintenance
100
Vulnerability
99.6
License
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
349 Stars
94 Commits
19 Forks
2 Watching
4 Branches
6 Contributors
Updated on 27 Nov 2024
TypeScript (100%)
Cumulative downloads
Total Downloads
Last day
3.2%
47,615
Compared to previous day
Last week
9.9%
281,553
Compared to previous week
Last month
20%
1,081,915
Compared to previous month
Last year
174.6%
4,463,169
Compared to previous year
2
generate TypeScript types from your Zod schema
npm install zod-to-ts zod typescript
1import { z } from 'zod' 2import { zodToTs } from 'zod-to-ts' 3 4// define your Zod schema 5const UserSchema = z.object({ 6 username: z.string(), 7 age: z.number(), 8 inventory: z.object({ 9 name: z.string(), 10 itemId: z.number(), 11 }).array(), 12}) 13 14// pass schema and name of type/identifier 15const { node } = zodToTs(UserSchema, 'User')
result:
1{ 2 username: string 3 age: number 4 inventory: { 5 name: string 6 itemId: number 7 }[] 8}
You must pass in the identifier User
or it will default to Identifier
. This is necessary to handle cases like recursive types and native enums. zodToTs()
only returns the type value, not the actual type declaration. If you want to add an identifier to the type and create a type declaration, you can use the createTypeAlias()
utility:
1import { createTypeAlias, zodToTs } from 'zod-to-ts'
2
3const identifier = 'User'
4const { node } = zodToTs(UserSchema, identifier)
5const typeAlias = createTypeAlias(
6 node,
7 identifier,
8 // optionally pass a comment
9 // comment: UserSchema.description
10)
result:
1type User = { 2 username: string 3}
zodToTs()
and createTypeAlias()
return a TS AST nodes, so if you want to get the node as a string, you can use the printNode()
utility.
zodToTs()
:
1import { printNode, zodToTs } from 'zod-to-ts' 2 3const identifier = 'User' 4const { node } = zodToTs(UserSchema, identifier) 5const nodeString = printNode(node)
result:
"{
username: string
age: number
inventory: {
name: string
itemId: number
}[]
}"
createTypeAlias()
:
1import { createTypeAlias, printNode, zodToTs } from 'zod-to-ts' 2 3const identifier = 'User' 4const { node } = zodToTs(UserSchema, identifier) 5const typeAlias = createTypeAlias(node, identifier) 6const nodeString = printNode(typeAlias)
result:
"type User = {
username: string
age: number
inventory: {
name: string
itemId: number
}[]
}"
You can use withGetType
to override a type, which is useful when more information is needed to determine the actual type. Unfortunately, this means working with the TS AST:
1import { z } from 'zod' 2import { withGetType, zodToTs } from 'zod-to-ts' 3 4const DateSchema = withGetType( 5 z.instanceof(Date), 6 (ts) => ts.factory.createIdentifier('Date'), 7) 8 9const ItemSchema = z.object({ 10 name: z.string(), 11 date: DateSchema, 12}) 13 14const { node } = zodToTs(ItemSchema, 'Item')
result without withGetType
override:
1type Item = { 2 name: string 3 date: any 4}
result with override:
1type Item = { 2 name: string 3 date: Date 4}
TypeScript AST Viewer can help a lot with this if you are having trouble referencing something. It even provides copy-pastable code!
Lazy types default to referencing the root type (User
in the following example). It is impossible to determine what it is referencing otherwise.
1// Zod cannot infer types when you use the z.lazy 2// so you must define it 3import { z } from 'zod' 4type User = { 5 username: string 6 friends: User[] 7} 8 9const UserSchema: z.ZodSchema<User> = z.object({ 10 username: z.string(), 11 friends: z.lazy(() => UserSchema).array(), 12}) 13 14const { node } = zodToTs(UserSchema, 'User')
result:
1type User = { 2 username: string 3 friends: User[] 4}
But what happens when the schema looks like this?
1type User = { 2 username: string 3 item: { 4 name: string 5 itemId: string 6 } 7 friends: User[] 8} 9 10// essentially when you are referencing a different field 11// and not the root type 12const friendItems = z.lazy(() => UserSchema.item).array() 13 14const UserSchema: z.ZodSchema<User> = z.object({ 15 username: z.string(), 16 item: z.object({ 17 name: z.string(), 18 id: z.number(), 19 }), 20 friendItems, 21}) 22 23const { node } = zodToTs(UserSchema, 'User')
result:
1{ 2 username: string 3 item: { 4 name: string 5 id: number 6 } 7 friendItems: User[] 8}
friendItems
will still have the User
type even though it is actually referencing UserSchema["item"]
. You must provide the actual type using withGetType
:
1import { z } from 'zod'
2import { withGetType } from 'zod-to-ts'
3type User = {
4 username: string
5 item: {
6 name: string
7 id: number
8 }
9 friends: User[]
10}
11
12const friendItems: z.Schema<User['item'][]> = withGetType(
13 z.lazy(() => UserSchema.item).array(),
14 // return a TS AST node
15 (ts, identifier) =>
16 ts.factory.createIndexedAccessTypeNode(
17 ts.factory.createTypeReferenceNode(
18 ts.factory.createIdentifier(identifier),
19 undefined,
20 ),
21 ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral('item')),
22 ),
23)
24
25const UserSchema: z.ZodSchema<User> = z.object({
26 username: z.string(),
27 item: z.object({
28 name: z.string(),
29 id: z.number(),
30 }),
31 friendItems,
32})
33
34const { node } = zodToTs(UserSchema, 'User')
result:
1{ 2 username: string 3 item: { 4 name: string 5 id: number 6 } 7 friendItems: User['item'][] 8}
z.enum()
is always preferred, but sometimes z.nativeEnum()
is necessary. z.nativeEnum()
works similarly to z.lazy()
in that the identifier of the enum cannot be determined:
1import { z } from 'zod' 2import { withGetType } from 'zod-to-ts' 3 4enum Fruit { 5 Apple = 'apple', 6 Banana = 'banana', 7 Cantaloupe = 'cantaloupe', 8} 9 10const fruitNativeEnum: = z.nativeEnum( 11 Fruit, 12) 13 14const TreeSchema = z.object({ 15 fruit: fruitNativeEnum, 16})
result:
1{ 2 fruit: unknown 3}
There are three ways to solve this: provide an identifier to it or resolve all the enums inside zodToTs()
.
Option 1 - providing an identifier using withGetType()
:
1import { z } from 'zod' 2import { withGetType, zodToTs } from 'zod-to-ts' 3 4enum Fruit { 5 Apple = 'apple', 6 Banana = 'banana', 7 Cantaloupe = 'cantaloupe', 8} 9 10const fruitNativeEnum = withGetType( 11 z.nativeEnum( 12 Fruit, 13 ), 14 // return an identifier that will be used on the enum type 15 (ts) => ts.factory.createIdentifier('Fruit'), 16) 17 18const TreeSchema = z.object({ 19 fruit: fruitNativeEnum, 20}) 21 22const { node } = zodToTs(TreeSchema)
result:
1{ 2 fruit: Fruit 3}
Option 2 - resolve enums. This is the same as before, but you just need to pass an option:
1const TreeTSType = zodToTs(TreeSchema, undefined, { nativeEnums: 'resolve' })
result:
1{ 2 node: { 3 fruit: Fruit 4 }, 5 store: { 6 nativeEnums: [ 7 enum Fruit { 8 Apple = 'apple', 9 Banana = 'banana', 10 Cantaloupe = 'cantaloupe', 11 } 12 ] 13 } 14}
Note: These are not the actual values, they are TS representation. The actual values are TS AST nodes.
This option allows you to embed the enums before the schema without actually depending on an external enum type.
Option 3 - convert to union. This is the same as how ZodEnum created by z.enum([...]) is handled, but need to pass an option:
1const { node } = zodToTs(TreeSchema, undefined, {
2 nativeEnums: 'union',
3})
result:
1{ 2 fruit: 'apple' | 'banana' | 'cantaloupe' 3}
Note: These are not the actual values, they are TS representation. The actual values are TS AST nodes.
No vulnerabilities found.
No security vulnerabilities found.