0Pricing
TypeScript Academy · Lesson

Inferring Types from Schemas

Derive static types directly from Zod schemas.

Inferring Types from Schemas is a free TypeScript Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Schemas Carry Type Information

A Zod schema knows the TypeScript type it validates. z.infer extracts that type, so you write the shape once.

import { z } from "zod";
const userSchema = z.object({ name: z.string(), age: z.number() });
type User = z.infer<typeof userSchema>;
// User is { name: string; age: number }

The z.infer Utility

z.infer<typeof schema> produces the static type that the schema validates. Note the typeof: you pass the schema value.

import { z } from "zod";
const tagSchema = z.array(z.string());
type Tags = z.infer<typeof tagSchema>; // string[]

Single Source of Truth

Without inference you would maintain a type and a schema separately and they could drift. z.infer keeps them perfectly in sync.

import { z } from "zod";
const schema = z.object({ id: z.number(), email: z.string() });
type Account = z.infer<typeof schema>;
// Change the schema, the type updates automatically.

Inferring Nested Types

Inference handles nested objects and arrays, producing the full nested TypeScript type from one schema.

import { z } from "zod";
const postSchema = z.object({
  title: z.string(),
  author: z.object({ name: z.string() }),
  tags: z.array(z.string())
});
type Post = z.infer<typeof postSchema>;
// Post.author.name is string

Using the Inferred Type

Use the inferred type anywhere you would use a hand-written type: function parameters, variables, return types.

import { z } from "zod";
const userSchema = z.object({ name: z.string(), age: z.number() });
type User = z.infer<typeof userSchema>;
function greet(u: User): string {
  return "Hi " + u.name;
}

Parse Returns the Inferred Type

schema.parse returns a value already typed as the inferred type, so downstream code is fully typed.

import { z } from "zod";
const userSchema = z.object({ name: z.string(), age: z.number() });
type User = z.infer<typeof userSchema>;
const raw: unknown = { name: "Ada", age: 36 };
const user: User = userSchema.parse(raw); // typed and validated

Optional and Nullable in the Type

Schema modifiers flow into the inferred type. An .optional() field becomes optional in TypeScript.

import { z } from "zod";
const schema = z.object({
  name: z.string(),
  nickname: z.string().optional()
});
type P = z.infer<typeof schema>;
// P is { name: string; nickname?: string }

Inferring From Arrays of Objects

Combine z.array and z.object and the inferred type is an array of the object type.

import { z } from "zod";
const usersSchema = z.array(z.object({ id: z.number() }));
type Users = z.infer<typeof usersSchema>;
// Users is { id: number }[]

Why typeof Is Needed

The schema is a value, so you reference its type with typeof schema before passing it to z.infer.

import { z } from "zod";
const s = z.string();
type S = z.infer<typeof s>; // string
// z.infer<s> would be wrong: s is a value, not a type.

Inference Across Module Boundaries

Export both the schema and its inferred type so other modules can validate and use the same shape consistently.

import { z } from "zod";
export const userSchema = z.object({ name: z.string() });
export type User = z.infer<typeof userSchema>;
// Consumers import both the runtime schema and the type.

One Definition, Two Worlds

The schema serves runtime validation; z.infer serves compile-time typing. One declaration powers both, eliminating duplication.

import { z } from "zod";
const configSchema = z.object({ port: z.number(), host: z.string() });
type Config = z.infer<typeof configSchema>;
// Validate at runtime, type at compile time, no drift.

Quick Check: Inferring Types

Test your understanding of inferring types from schemas.

Recap: Inferring Types From Schemas

You learned that z.infer<typeof schema> derives a TypeScript type from a Zod schema, giving a single source of truth for validation and types, including nested, optional, and array shapes.

import { z } from "zod";
const userSchema = z.object({ name: z.string(), age: z.number() });
type User = z.infer<typeof userSchema>;
// User stays in sync with the schema automatically.

Frequently asked questions

Is the “Inferring Types from Schemas” lesson free?

Yes — the full text of “Inferring Types from Schemas” is free to read here on the web, and the TypeScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.

What will I learn in “Inferring Types from Schemas”?

Derive static types directly from Zod schemas. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start TypeScript Academy?

No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Inferring Types from Schemas” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this TypeScript Academy lesson?

Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Zod Schema Basics
  2. Inferring Types from Schemas
  3. parse vs safeParse
  4. Composing and Refining Schemas
← Back to TypeScript Academy