본문으로 건너뛰기

마이그레이션 가이드

이 마이그레이션 가이드는 Zod 4의 호환성을 깨는 변경을 영향이 큰 순서부터 작은 순서까지 정리합니다. Zod 4의 성능 개선과 새로운 기능을 자세히 알아보려면 소개 글을 읽어 보세요.

npm install zod@^4.0.0

Zod의 여러 동작과 API가 더욱 직관적이고 일관되게 개선되었습니다. 이 문서에서 설명하는 호환성을 깨는 변경은 Zod 사용자의 편의성을 크게 높이는 경우가 많습니다. 이 가이드를 처음부터 끝까지 읽어 보기를 강력히 권장합니다.

오류 사용자 정의

Zod 4는 오류 사용자 정의 API를 하나의 통합된 error 매개변수로 표준화합니다. 이전에는 Zod의 오류 사용자 정의 API가 여러 곳에 흩어져 있고 일관되지 않았지만, Zod 4에서 이를 정리했습니다.

message 매개변수 지원 중단 예정

message 매개변수를 error로 대체합니다. 기존 message 매개변수도 계속 지원되지만 지원 중단 예정입니다.

z.string().min(5, { error: "Too short." });
z.string().min(5, { message: "Too short." });

invalid_type_errorrequired_error 제거

invalid_type_error / required_error 매개변수는 제거되었습니다. 이들은 오래전 errorMap보다 간결하게 오류를 사용자 정의하는 방법으로 급히 추가되었지만, 여러 함정이 있었습니다(errorMap과 함께 사용할 수 없는 등). 또한 Zod의 실제 이슈 코드와도 맞지 않습니다(required 이슈 코드는 존재하지 않습니다).

이제 새로운 error 매개변수로 같은 동작을 깔끔하게 표현할 수 있습니다.

z.string({ 
error: (issue) => issue.input === undefined
? "This field is required"
: "Not a string"
});
z.string({ 
required_error: "This field is required",
invalid_type_error: "Not a string",
});

errorMap 제거

이름이 error로 변경되었습니다.

이제 오류 맵은 일반 string도 반환할 수 있습니다({message: string} 대신). 또한 undefined를 반환해 체인의 다음 오류 맵으로 제어권을 넘기도록 Zod에 지시할 수 있습니다.

z.string().min(5, {
error: (issue) => {
if (issue.code === "too_small") {
return `Value must be >${issue.minimum}`
}
},
});
z.string({
errorMap: (issue, ctx) => {
if (issue.code === "too_small") {
return { message: `Value must be >${issue.minimum}` };
}
return { message: ctx.defaultError };
},
});

ZodError

이슈 형식 변경

이슈 형식이 대폭 간소화되었습니다.

import * as z from "zod"; // v4

type IssueFormats =
| z.core.$ZodIssueInvalidType
| z.core.$ZodIssueTooBig
| z.core.$ZodIssueTooSmall
| z.core.$ZodIssueInvalidStringFormat
| z.core.$ZodIssueNotMultipleOf
| z.core.$ZodIssueUnrecognizedKeys
| z.core.$ZodIssueInvalidValue
| z.core.$ZodIssueInvalidUnion
| z.core.$ZodIssueInvalidKey // new: used for z.record/z.map
| z.core.$ZodIssueInvalidElement // new: used for z.map/z.set
| z.core.$ZodIssueCustom;

다음은 Zod 3 이슈 타입과 이에 대응하는 Zod 4 타입의 목록입니다.

import * as z from "zod"; // v3

export type IssueFormats =
| z.ZodInvalidTypeIssue // ♻️ renamed to z.core.$ZodIssueInvalidType
| z.ZodTooBigIssue // ♻️ renamed to z.core.$ZodIssueTooBig
| z.ZodTooSmallIssue // ♻️ renamed to z.core.$ZodIssueTooSmall
| z.ZodInvalidStringIssue // ♻️ z.core.$ZodIssueInvalidStringFormat
| z.ZodNotMultipleOfIssue // ♻️ renamed to z.core.$ZodIssueNotMultipleOf
| z.ZodUnrecognizedKeysIssue // ♻️ renamed to z.core.$ZodIssueUnrecognizedKeys
| z.ZodInvalidUnionIssue // ♻️ renamed to z.core.$ZodIssueInvalidUnion
| z.ZodCustomIssue // ♻️ renamed to z.core.$ZodIssueCustom
| z.ZodInvalidEnumValueIssue // ❌ merged in z.core.$ZodIssueInvalidValue
| z.ZodInvalidLiteralIssue // ❌ merged into z.core.$ZodIssueInvalidValue
| z.ZodInvalidUnionDiscriminatorIssue // ❌ throws an Error at schema creation time
| z.ZodInvalidArgumentsIssue // ❌ z.function throws ZodError directly
| z.ZodInvalidReturnTypeIssue // ❌ z.function throws ZodError directly
| z.ZodInvalidDateIssue // ❌ merged into invalid_type
| z.ZodInvalidIntersectionTypesIssue // ❌ removed (throws regular Error)
| z.ZodNotFiniteIssue // ❌ infinite values no longer accepted (invalid_type)

일부 Zod 4 이슈 타입이 병합, 제거 또는 수정되었지만 각 이슈의 구조는 Zod 3의 대응 타입과 비슷하게 유지됩니다(대부분은 동일합니다). 모든 이슈는 여전히 Zod 3과 같은 기본 인터페이스를 따르므로 일반적인 오류 처리 로직 대부분은 수정 없이 작동합니다.

export interface $ZodIssueBase {
readonly code?: string;
readonly input?: unknown;
readonly path: PropertyKey[];
readonly message: string;
}

오류 맵 우선순위 변경

오류 맵의 우선순위가 더 일관되도록 변경되었습니다. 특히 .parse()에 전달한 오류 맵은 더 이상 스키마 수준 오류 맵보다 우선하지 않습니다.

const mySchema = z.string({ error: () => "Schema-level error" });

// in Zod 3
mySchema.parse(12, { error: () => "Contextual error" }); // => "Contextual error"

// in Zod 4
mySchema.parse(12, { error: () => "Contextual error" }); // => "Schema-level error"

.format() 지원 중단 예정

.format() 메서드는 ZodError에서 지원 중단 예정입니다. 대신 최상위 z.treeifyError() 함수를 사용하세요. 자세한 내용은 오류 형식화 문서를 읽어 보세요.

.flatten() 지원 중단 예정

.flatten() 메서드도 ZodError에서 지원 중단 예정입니다. 대신 최상위 z.treeifyError() 함수를 사용하세요. 자세한 내용은 오류 형식화 문서를 읽어 보세요.

.formErrors 제거

이 API는 .flatten()과 동일했습니다. 역사적인 이유로 존재하며 문서화되어 있지 않습니다.

.errors 제거

이 API는 Zod v3에서 .issues의 별칭이었지만 제거되었습니다. 대신 .issues를 사용하세요.

.addIssue().addIssues() 지원 중단 예정

필요하다면 err.issues 배열에 직접 추가하세요.

myError.issues.push({ 
// new issue
});

z.number()

무한대 값 허용 안 함

POSITIVE_INFINITYNEGATIVE_INFINITY는 더 이상 z.number()에 대한 유효한 값으로 간주되지 않습니다.

.safe()는 더 이상 부동 소수점 수를 허용하지 않음

Zod 3에서 z.number().safe()는 지원 중단 예정입니다. 이제 .int()와 동일하게 동작합니다(아래 참고). 중요한 점은 더 이상 부동 소수점 수를 허용하지 않는다는 것입니다.

.int()는 안전한 정수만 허용

z.number().int() API는 더 이상 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER 범위를 벗어난 안전하지 않은 정수를 허용하지 않습니다. 이 범위를 벗어난 정수를 사용하면 예기치 않은 반올림 오류가 발생합니다. (또한 z.int()로 전환하는 것이 좋습니다.)

z.string() 변경 사항

.email() 등 지원 중단 예정

문자열 형식은 이제 단순한 내부 세부 검증이 아니라 ZodString하위 클래스로 표현됩니다. 이에 따라 관련 API가 최상위 z 네임스페이스로 이동했습니다. 최상위 API는 더 간결하고 트리 셰이킹도 더 잘됩니다.

z.email();
z.uuid();
z.url();
z.emoji(); // validates a single emoji character
z.base64();
z.base64url();
z.nanoid();
z.cuid();
z.cuid2();
z.ulid();
z.ipv4();
z.ipv6();
z.cidrv4(); // ip range
z.cidrv6(); // ip range
z.iso.date();
z.iso.time();
z.iso.datetime();
z.iso.duration();

메서드 형태(z.string().email())도 계속 존재하고 이전처럼 작동하지만 지원 중단 예정입니다.

z.string().email(); // ❌ deprecated
z.email(); // ✅

더 엄격해진 .uuid()

이제 z.uuid()는 RFC 9562/4122 사양에 맞춰 UUID를 더 엄격하게 검증합니다. 특히 사양에 따라 변형 비트는 10이어야 합니다. 더 관대한 "UUID와 유사한" 검증기가 필요하면 z.guid()를 사용하세요.

z.uuid(); // RFC 9562/4122 compliant UUID
z.guid(); // any 8-4-4-4-12 hex pattern

.base64url()에서 패딩 제거

z.base64url()(이전의 z.string().base64url())은 더 이상 패딩을 허용하지 않습니다. 일반적으로 base64url 문자열은 패딩이 없고 URL에 안전한 형태인 것이 바람직합니다.

z.string().ip() 제거

이 기능은 별도의 .ipv4().ipv6() 메서드로 대체되었습니다. 두 형식을 모두 허용해야 한다면 z.union()으로 결합하세요.

z.string().ip() // ❌
z.ipv4() // ✅
z.ipv6() // ✅

z.string().ipv6() 업데이트

이제 이전의 정규 표현식 방식보다 훨씬 견고한 new URL() 생성자를 사용해 검증합니다. 이전에는 검증을 통과했던 잘못된 값이 이제 실패할 수 있습니다.

z.string().cidr() 제거

마찬가지로 이 기능은 별도의 .cidrv4().cidrv6() 메서드로 대체되었습니다. 두 형식을 모두 허용해야 한다면 z.union()으로 결합하세요.

z.string().cidr() // ❌
z.cidrv4() // ✅
z.cidrv6() // ✅

z.coerce 변경 사항

이제 모든 z.coerce 스키마의 입력 타입은 unknown입니다.

const schema = z.coerce.string();
type schemaInput = z.input<typeof schema>;

// Zod 3: string;
// Zod 4: unknown;

z.coerce.* 필드가 있는 객체 스키마에서 키가 누락되면 이제 오류가 발생합니다. 명시적인 대체 값을 선언하려면 .default()를 사용하세요.

const schema = z.object({ foo: z.coerce.boolean() });
schema.parse({});

// Zod 3: { foo: false }
// Zod 4: ZodError: Invalid input: expected nonoptional, received undefined

.default() 변경 사항

.default()가 적용되는 방식이 미묘하게 변경되었습니다. 입력이 undefined이면 ZodDefault는 파싱 과정을 단축하고 기본값을 반환합니다. 기본값은 출력 타입에 할당할 수 있어야 합니다.

const schema = z.string()
.transform(val => val.length)
.default(0); // should be a number
schema.parse(undefined); // => 0

Zod 3에서 .default()입력 타입과 일치하는 값을 요구했습니다. ZodDefault는 파싱을 단축하지 않고 기본값을 파싱했습니다. 따라서 기본값은 스키마의 입력 타입에 할당할 수 있어야 했습니다.

// Zod 3
const schema = z.string()
.transform(val => val.length)
.default("tuna");
schema.parse(undefined); // => 4

이전 동작을 재현하기 위해 Zod는 새로운 .prefault() API를 제공합니다. "pre-parse default"의 줄임말입니다.

// Zod 3
const schema = z.string()
.transform(val => val.length)
.prefault("tuna");
schema.parse(undefined); // => 4

z.object()

선택적 필드 내부에도 기본값 적용

선택적 필드 내부의 속성에도 기본값이 적용됩니다. 이는 기대에 더 잘 부합하고 Zod 3의 오래된 사용성 문제를 해결합니다. 키의 존재 여부 등에 의존하는 코드 경로가 깨질 수 있는 미묘한 변경입니다.

const schema = z.object({
a: z.string().default("tuna").optional(),
});

schema.parse({});
// Zod 4: { a: "tuna" }
// Zod 3: {}

.strict().passthrough() 지원 중단 예정

일반적으로 이 메서드들은 더 이상 필요하지 않습니다. 대신 최상위 z.strictObject()z.looseObject() 함수를 사용하세요.

// Zod 3
z.object({ name: z.string() }).strict();
z.object({ name: z.string() }).passthrough();

// Zod 4
z.strictObject({ name: z.string() });
z.looseObject({ name: z.string() });

이 메서드들은 이전 버전과의 호환성을 위해 계속 제공되며 제거되지 않습니다. 레거시로 간주됩니다.

.strip() 지원 중단 예정

이는 z.object()의 기본 동작이므로 원래부터 특별히 유용하지 않았습니다. 엄격한 객체를 "일반" 객체로 변환하려면 z.object(A.shape)를 사용하세요.

.nonstrict() 제거

.strip()의 오래전에 지원 중단된 별칭이 제거되었습니다.

.deepPartial() 제거

이 기능은 Zod 3에서 오랫동안 지원 중단 예정이었고 Zod 4에서 제거되었습니다. 이 API를 직접 대체하는 방법은 없습니다. 구현에 여러 함정이 있었으며 일반적으로 안티패턴으로 간주됩니다.

z.unknown() 선택성 변경

이제 추론된 타입에서 z.unknown()z.any() 타입은 "키가 선택적"인 것으로 표시되지 않습니다.

const mySchema = z.object({
a: z.any(),
b: z.unknown()
});
// Zod 3: { a?: any; b?: unknown };
// Zod 4: { a: any; b: unknown };

v4.4.0부터 파싱 시점에도 키가 필요합니다. Zod 4.0–4.3은 위에서 추론된 타입과 달리 누락된 키를 허용했지만, 키를 필수로 바꾼 것은 타입 건전성을 위한 수정입니다.

mySchema.parse({}); // ❌ (✅ in v4.3 and earlier)
mySchema.parse({ a: undefined, b: undefined }); // ✅

// use .optional() for a key that may be absent
z.object({ a: z.any().optional() }).parse({}); // ✅

.merge() 지원 중단 예정

.merge() 메서드는 ZodObject에서 .extend()로 대체되어 지원 중단 예정입니다. .extend()는 같은 기능을 제공하고 엄격성 상속의 모호함을 피하며 TypeScript 성능도 더 좋습니다.

// .merge (deprecated)
const ExtendedSchema = BaseSchema.merge(AdditionalSchema);

// .extend (recommended)
const ExtendedSchema = BaseSchema.extend(AdditionalSchema.shape);

// or use destructuring (best tsc performance)
const ExtendedSchema = z.object({
...BaseSchema.shape,
...AdditionalSchema.shape,
});

참고: TypeScript 성능을 더 높이려면 .extend() 대신 객체 펼침 구문을 사용해 보세요. 자세한 내용은 API 문서를 참고하세요.

z.nativeEnum() 지원 중단 예정

이제 z.nativeEnum() 함수는 z.enum()으로 대체되어 지원 중단 예정입니다. enum과 유사한 입력을 지원하도록 z.enum() API가 오버로드되었습니다.

enum Color {
Red = "red",
Green = "green",
Blue = "blue",
}

const ColorSchema = z.enum(Color); // ✅

ZodEnum 리팩터링의 일부로 오래전에 지원 중단되었거나 중복된 여러 기능이 제거되었습니다. 모두 같은 기능이었으며 역사적인 이유로만 존재했습니다.

ColorSchema.enum.Red; // ✅ => "Red" (canonical API)
ColorSchema.Enum.Red; // ❌ removed
ColorSchema.Values.Red; // ❌ removed

z.array()

.nonempty() 타입 변경

이제 z.array().min(1)과 동일하게 동작합니다. 추론되는 타입은 변경되지 않습니다.

const NonEmpty = z.array(z.string()).nonempty();

type NonEmpty = z.infer<typeof NonEmpty>;
// Zod 3: [string, ...string[]]
// Zod 4: string[]

이전 동작은 이제 z.tuple()과 "rest" 인자로 더 정확하게 표현할 수 있습니다. TypeScript의 타입 시스템에도 더 잘 맞습니다.

z.tuple([z.string()], z.string());
// => [string, ...string[]]

z.promise() 지원 중단 예정

z.promise()를 사용할 이유는 거의 없습니다. 입력이 Promise일 수 있다면 Zod로 파싱하기 전에 await하면 됩니다.

z.promise를 사용해 z.function()과 함께 비동기 함수를 정의했다면 이제 그럴 필요도 없습니다. 아래 ZodFunction 섹션을 참고하세요.

z.function()

z.function()의 결과는 더 이상 Zod 스키마가 아닙니다. 대신 Zod로 검증하는 함수를 정의하는 독립적인 "함수 팩토리" 역할을 합니다. API도 변경되어 inputoutput 스키마를 미리 정의하며, 더 이상 args().returns() 메서드를 사용하지 않습니다.

const myFunction = z.function({
input: [z.object({
name: z.string(),
age: z.number().int(),
})],
output: z.string(),
});

myFunction.implement((input) => {
return `Hello ${input.name}, you are ${input.age} years old.`;
});
const myFunction = z.function()
.args(z.object({
name: z.string(),
age: z.number().int(),
}))
.returns(z.string());

myFunction.implement((input) => {
return `Hello ${input.name}, you are ${input.age} years old.`;
});

함수 타입을 가진 Zod 스키마가 꼭 필요하다면 이 우회 방법을 고려하세요.

.implementAsync() 추가

비동기 함수를 정의할 때는 implementAsync()을 사용하고 implement()은 사용하지 마세요.

myFunction.implementAsync(async (input) => {
return `Hello ${input.name}, you are ${input.age} years old.`;
});

.refine()

타입 술어 무시

Zod 3에서는 타입 술어를 세부 검증 함수로 전달하면 스키마의 타입을 좁힐 수 있었습니다. 문서화된 기능은 아니었지만 몇몇 이슈에서 논의되었습니다. 이제는 더 이상 타입을 좁히지 않습니다.

const mySchema = z.unknown().refine((val): val is string => {
return typeof val === "string"
});

type MySchema = z.infer<typeof mySchema>;
// Zod 3: `string`
// Zod 4: still `unknown`

ctx.path 제거

Zod의 새 파싱 아키텍처는 path 배열을 즉시 계산하지 않습니다. 이 변경은 Zod 4의 획기적인 성능 향상을 가능하게 하는 데 필요했습니다.

z.string().superRefine((val, ctx) => {
ctx.path; // ❌ no longer available
});

두 번째 인자로 전달하는 함수 제거

다음과 같은 위험한 오버로드가 제거되었습니다.

const longString = z.string().refine(
(val) => val.length > 10,
(val) => ({ message: `${val} is not more than 10 characters` })
);

z.ostring() 등 제거

문서화되지 않은 편의 메서드 z.ostring(), z.onumber() 등이 제거되었습니다. 선택적 문자열 스키마를 정의하는 축약 메서드였습니다.

z.literal()

symbol 지원 제거

심벌은 리터럴 값으로 간주되지 않으며 ===로 단순 비교할 수도 없습니다. 이는 Zod 3의 누락 사항이었습니다.

정적 .create() 팩토리 제거

이전에는 모든 Zod 클래스가 정적 .create() 메서드를 정의했습니다. 이제는 독립적인 팩토리 함수로 구현됩니다.

z.ZodString.create(); // ❌ 

z.record()

단일 인자 사용 방식 제거

이전에는 z.record()를 인자 하나로 사용할 수 있었지만 이제는 지원하지 않습니다.

// Zod 3
z.record(z.string()); // ✅

// Zod 4
z.record(z.string()); // ❌
z.record(z.string(), z.string()); // ✅

enum 지원 개선

레코드가 훨씬 더 똑똑해졌습니다. Zod 3에서는 enum을 z.record()의 키 스키마로 전달하면 부분 타입이 생성되었습니다.

const myRecord = z.record(z.enum(["a", "b", "c"]), z.number()); 
// { a?: number; b?: number; c?: number; }

Zod 4에서는 그렇지 않습니다. 추론된 타입은 예상한 형태가 되며 Zod는 완전성을 보장합니다. 즉, 파싱할 때 입력에 모든 enum 키가 존재하는지 확인합니다.

const myRecord = z.record(z.enum(["a", "b", "c"]), z.number());
// { a: number; b: number; c: number; }

선택적 키를 사용하는 이전 동작을 재현하려면 z.partialRecord()를 사용하세요.

const myRecord = z.partialRecord(z.enum(["a", "b", "c"]), z.number());
// { a?: number; b?: number; c?: number; }

z.intersection()

병합 충돌 시 Error를 던짐

Zod 교집합은 입력을 두 스키마로 파싱한 다음 결과를 병합합니다. Zod 3에서는 결과를 병합할 수 없을 때 ZodError를 던졌으며, 여기에는 특수한 "invalid_intersection_types" 이슈가 담겼습니다.

Zod 4에서는 대신 일반 Error를 던집니다. 병합할 수 없는 결과가 존재한다는 것은 서로 호환되지 않는 두 타입을 교차한 스키마의 구조적 문제를 의미합니다. 따라서 검증 오류보다 일반 오류가 더 적절합니다.

내부 변경 사항

일반적인 Zod 사용자는 이 줄 아래의 내용을 대부분 무시해도 됩니다. 이러한 변경은 사용자에게 노출되는 z API에 영향을 주지 않습니다.

여기에 모두 나열하기 어려울 만큼 내부 변경이 많지만, 특정 구현 세부 사항에 의도적으로 또는 의도치 않게 의존하는 일반 사용자에게는 일부가 중요할 수 있습니다. 특히 Zod를 기반으로 도구를 구축하는 라이브러리 작성자에게 중요한 내용입니다.

제네릭 변경

여러 클래스의 제네릭 구조가 변경되었습니다. 그중 가장 중요한 것은 ZodType 기본 클래스의 변화일 것입니다.

// Zod 3
class ZodType<Output, Def extends z.ZodTypeDef, Input = Output> {
// ...
}

// Zod 4
class ZodType<Output = unknown, Input = unknown> {
// ...
}

두 번째 제네릭 Def는 완전히 제거되었습니다. 이제 기본 클래스는 OutputInput만 추적합니다. 이전에는 Input의 기본값이 Output이었지만 이제는 unknown입니다. 덕분에 z.ZodType을 사용하는 제네릭 함수가 많은 경우 더 직관적으로 동작합니다.

function inferSchema<T extends z.ZodType>(schema: T): T {
return schema;
};

inferSchema(z.string()); // z.ZodString

z.ZodTypeAny는 더 이상 필요하지 않습니다. 대신 z.ZodType을 사용하세요.

z.core 추가

Zod와 Zod Mini가 코드를 공유하기 쉽도록 여러 유틸리티 함수와 타입이 새로운 zod/v4/core 하위 패키지로 이동했습니다.

import * as z from "zod/v4/core";

function handleError(iss: z.$ZodError) {
// do stuff
}

편의를 위해 zod/v4/core의 내용은 zodzod/mini에서도 z.core 네임스페이스 아래로 다시 내보냅니다.

import * as z from "zod";

function handleError(iss: z.core.$ZodError) {
// do stuff
}

코어 하위 라이브러리의 구성 요소에 관한 자세한 내용은 Zod Core 문서를 참고하세요.

._def 이동

._def 속성은 ._zod.def로 이동했습니다. 모든 내부 정의의 구조는 변경될 수 있습니다. 이는 라이브러리 작성자에게 중요하지만 여기에서 모두 문서화하지는 않습니다.

ZodEffects 제거

사용자에게 노출되는 API에는 영향을 주지 않지만 주목할 만한 내부 변경입니다. Zod가 세부 검증을 처리하는 방식을 더 크게 재구성한 작업의 일부입니다.

이전에는 세부 검증과 변환이 모두 ZodEffects라는 래퍼 클래스 안에 있었습니다. 따라서 둘 중 하나를 스키마에 추가하면 원본 스키마를 ZodEffects 인스턴스로 감쌌습니다. Zod 4에서는 세부 검증이 스키마 자체 안에 존재합니다. 더 정확히 말하면 각 스키마에는 "검사" 배열이 있습니다. "검사"는 Zod 4에 새로 도입된 개념으로, z.toLowerCase()처럼 잠재적으로 부수 효과가 있는 변환까지 포함하도록 세부 검증 개념을 일반화합니다.

이는 여러 검증을 조합하기 위해 .check() 메서드에 크게 의존하는 Zod Mini API에서 특히 잘 드러납니다.

import * as z from "zod/mini";

z.string().check(
z.minLength(10),
z.maxLength(100),
z.toLowerCase(),
z.trim(),
);

ZodTransform 추가

한편 변환은 전용 ZodTransform 클래스로 이동했습니다. 이 스키마 클래스는 입력 변환을 나타냅니다. 이제 독립적인 변환도 정의할 수 있습니다.

import * as z from "zod";

const schema = z.transform(input => String(input));

schema.parse(12); // => "12"

주로 ZodPipe와 함께 사용합니다. 이제 .transform() 메서드는 ZodPipe 인스턴스를 반환합니다.

z.string().transform(val => val); // ZodPipe<ZodString, ZodTransform>

ZodPreprocess 제거

.transform()과 마찬가지로 z.preprocess() 함수는 이제 ZodPipe 인스턴스를 반환하며 전용 ZodPreprocess 인스턴스를 반환하지 않습니다.

z.preprocess(val => val, z.string()); // ZodPipe<ZodTransform, ZodString>

ZodBranded 제거

이제 브랜딩은 전용 ZodBranded 클래스 대신 추론된 타입을 직접 수정하는 방식으로 처리합니다. 사용자에게 노출되는 API는 그대로입니다.