@kood/claude-code 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +297 -0
  3. package/package.json +47 -0
  4. package/templates/hono/CLAUDE.md +376 -0
  5. package/templates/hono/docs/deployment/cloudflare.md +328 -0
  6. package/templates/hono/docs/deployment/index.md +291 -0
  7. package/templates/hono/docs/git/index.md +180 -0
  8. package/templates/hono/docs/library/hono/error-handling.md +400 -0
  9. package/templates/hono/docs/library/hono/index.md +241 -0
  10. package/templates/hono/docs/library/hono/middleware.md +334 -0
  11. package/templates/hono/docs/library/hono/rpc.md +454 -0
  12. package/templates/hono/docs/library/hono/validation.md +328 -0
  13. package/templates/hono/docs/library/prisma/index.md +427 -0
  14. package/templates/hono/docs/library/zod/index.md +413 -0
  15. package/templates/hono/docs/mcp/context7.md +106 -0
  16. package/templates/hono/docs/mcp/index.md +94 -0
  17. package/templates/hono/docs/mcp/sequential-thinking.md +101 -0
  18. package/templates/hono/docs/mcp/sgrep.md +105 -0
  19. package/templates/hono/docs/skills/gemini-review/SKILL.md +220 -0
  20. package/templates/hono/docs/skills/gemini-review/references/checklists.md +136 -0
  21. package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +303 -0
  22. package/templates/tanstack-start/CLAUDE.md +279 -0
  23. package/templates/tanstack-start/docs/architecture/architecture.md +547 -0
  24. package/templates/tanstack-start/docs/deployment/cloudflare.md +346 -0
  25. package/templates/tanstack-start/docs/deployment/index.md +102 -0
  26. package/templates/tanstack-start/docs/deployment/nitro.md +211 -0
  27. package/templates/tanstack-start/docs/deployment/railway.md +364 -0
  28. package/templates/tanstack-start/docs/deployment/vercel.md +287 -0
  29. package/templates/tanstack-start/docs/design/accessibility.md +433 -0
  30. package/templates/tanstack-start/docs/design/color.md +235 -0
  31. package/templates/tanstack-start/docs/design/components.md +409 -0
  32. package/templates/tanstack-start/docs/design/index.md +107 -0
  33. package/templates/tanstack-start/docs/design/safe-area.md +317 -0
  34. package/templates/tanstack-start/docs/design/spacing.md +341 -0
  35. package/templates/tanstack-start/docs/design/tailwind-setup.md +470 -0
  36. package/templates/tanstack-start/docs/design/typography.md +324 -0
  37. package/templates/tanstack-start/docs/git/index.md +203 -0
  38. package/templates/tanstack-start/docs/guides/best-practices.md +753 -0
  39. package/templates/tanstack-start/docs/guides/getting-started.md +304 -0
  40. package/templates/tanstack-start/docs/guides/husky-lint-staged.md +303 -0
  41. package/templates/tanstack-start/docs/guides/prettier.md +189 -0
  42. package/templates/tanstack-start/docs/guides/project-templates.md +710 -0
  43. package/templates/tanstack-start/docs/library/better-auth/2fa.md +136 -0
  44. package/templates/tanstack-start/docs/library/better-auth/advanced.md +138 -0
  45. package/templates/tanstack-start/docs/library/better-auth/index.md +83 -0
  46. package/templates/tanstack-start/docs/library/better-auth/plugins.md +111 -0
  47. package/templates/tanstack-start/docs/library/better-auth/session.md +127 -0
  48. package/templates/tanstack-start/docs/library/better-auth/setup.md +123 -0
  49. package/templates/tanstack-start/docs/library/prisma/crud.md +218 -0
  50. package/templates/tanstack-start/docs/library/prisma/index.md +165 -0
  51. package/templates/tanstack-start/docs/library/prisma/relations.md +191 -0
  52. package/templates/tanstack-start/docs/library/prisma/schema.md +177 -0
  53. package/templates/tanstack-start/docs/library/prisma/setup.md +156 -0
  54. package/templates/tanstack-start/docs/library/prisma/transactions.md +140 -0
  55. package/templates/tanstack-start/docs/library/tanstack-query/index.md +146 -0
  56. package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +146 -0
  57. package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +196 -0
  58. package/templates/tanstack-start/docs/library/tanstack-query/setup.md +110 -0
  59. package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +170 -0
  60. package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +173 -0
  61. package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +171 -0
  62. package/templates/tanstack-start/docs/library/tanstack-start/index.md +114 -0
  63. package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +142 -0
  64. package/templates/tanstack-start/docs/library/tanstack-start/routing.md +163 -0
  65. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +128 -0
  66. package/templates/tanstack-start/docs/library/tanstack-start/setup.md +85 -0
  67. package/templates/tanstack-start/docs/library/zod/basic-types.md +186 -0
  68. package/templates/tanstack-start/docs/library/zod/complex-types.md +204 -0
  69. package/templates/tanstack-start/docs/library/zod/index.md +186 -0
  70. package/templates/tanstack-start/docs/library/zod/transforms.md +174 -0
  71. package/templates/tanstack-start/docs/library/zod/validation.md +208 -0
  72. package/templates/tanstack-start/docs/mcp/context7.md +204 -0
  73. package/templates/tanstack-start/docs/mcp/index.md +116 -0
  74. package/templates/tanstack-start/docs/mcp/sequential-thinking.md +180 -0
  75. package/templates/tanstack-start/docs/mcp/sgrep.md +174 -0
  76. package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +220 -0
  77. package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +150 -0
  78. package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +293 -0
@@ -0,0 +1,204 @@
1
+ # Zod - 복합 타입
2
+
3
+ > **상위 문서**: [Zod](./index.md)
4
+
5
+ ## 객체
6
+
7
+ ```typescript
8
+ const UserSchema = z.object({
9
+ name: z.string(),
10
+ email: z.email(), // v4 새 API
11
+ age: z.number().optional(), // 선택적 필드
12
+ })
13
+
14
+ // 검증
15
+ const result = UserSchema.parse({
16
+ name: 'john',
17
+ email: 'john@example.com',
18
+ age: 25,
19
+ })
20
+
21
+ // 안전한 검증
22
+ const safeResult = UserSchema.safeParse(data)
23
+ if (safeResult.success) {
24
+ console.log(safeResult.data)
25
+ } else {
26
+ console.log(safeResult.error)
27
+ }
28
+ ```
29
+
30
+ ### 객체 메서드
31
+
32
+ ```typescript
33
+ // 부분 객체 (모든 필드가 optional)
34
+ const PartialUser = UserSchema.partial()
35
+
36
+ // 필수 객체 (모든 필드가 required)
37
+ const RequiredUser = UserSchema.required()
38
+
39
+ // 필드 선택
40
+ const UserName = UserSchema.pick({ name: true })
41
+
42
+ // 필드 제외
43
+ const UserWithoutEmail = UserSchema.omit({ email: true })
44
+
45
+ // 확장
46
+ const ExtendedUser = UserSchema.extend({
47
+ role: z.enum(['admin', 'user']),
48
+ })
49
+
50
+ // 병합
51
+ const MergedSchema = UserSchema.merge(AnotherSchema)
52
+ ```
53
+
54
+ ### Strict/Loose 객체 (v4)
55
+
56
+ ```typescript
57
+ // v3
58
+ z.object({ name: z.string() }).strict() // 추가 키 에러
59
+ z.object({ name: z.string() }).passthrough() // 추가 키 통과
60
+
61
+ // v4 - 새로운 API
62
+ z.strictObject({ name: z.string() }) // 추가 키 에러
63
+ z.looseObject({ name: z.string() }) // 추가 키 통과
64
+ ```
65
+
66
+ ## 배열
67
+
68
+ ```typescript
69
+ z.array(z.string())
70
+ z.array(z.number()).min(1) // 최소 1개
71
+ z.array(z.number()).max(10) // 최대 10개
72
+ z.array(z.number()).length(5) // 정확히 5개
73
+ z.array(z.number()).nonempty() // 비어있지 않음
74
+ ```
75
+
76
+ ## 튜플
77
+
78
+ ```typescript
79
+ const tuple = z.tuple([
80
+ z.string(), // 첫 번째 요소
81
+ z.number(), // 두 번째 요소
82
+ ])
83
+
84
+ type Tuple = z.infer<typeof tuple>
85
+ // [string, number]
86
+ ```
87
+
88
+ ## 유니온
89
+
90
+ ```typescript
91
+ const StringOrNumber = z.union([z.string(), z.number()])
92
+ // 또는
93
+ const StringOrNumber = z.string().or(z.number())
94
+
95
+ type StringOrNumber = z.infer<typeof StringOrNumber>
96
+ // string | number
97
+ ```
98
+
99
+ ## Discriminated Union
100
+
101
+ ```typescript
102
+ const Shape = z.discriminatedUnion('type', [
103
+ z.object({ type: z.literal('circle'), radius: z.number() }),
104
+ z.object({ type: z.literal('rectangle'), width: z.number(), height: z.number() }),
105
+ ])
106
+
107
+ type Shape = z.infer<typeof Shape>
108
+ // { type: 'circle'; radius: number } | { type: 'rectangle'; width: number; height: number }
109
+ ```
110
+
111
+ ### v4 향상된 Discriminated Union
112
+
113
+ ```typescript
114
+ // 유니온 및 파이프 discriminator 지원
115
+ const MyResult = z.discriminatedUnion("status", [
116
+ // 단순 리터럴
117
+ z.object({ status: z.literal("aaa"), data: z.string() }),
118
+ // 유니온 discriminator
119
+ z.object({ status: z.union([z.literal("bbb"), z.literal("ccc")]) }),
120
+ // 파이프 discriminator
121
+ z.object({ status: z.literal("fail").transform(val => val.toUpperCase()) }),
122
+ ])
123
+
124
+ // 중첩 discriminated union
125
+ const BaseError = z.object({ status: z.literal("failed"), message: z.string() })
126
+
127
+ const MyResult2 = z.discriminatedUnion("status", [
128
+ z.object({ status: z.literal("success"), data: z.string() }),
129
+ z.discriminatedUnion("code", [
130
+ BaseError.extend({ code: z.literal(400) }),
131
+ BaseError.extend({ code: z.literal(401) }),
132
+ BaseError.extend({ code: z.literal(500) })
133
+ ])
134
+ ])
135
+ ```
136
+
137
+ ## Enum
138
+
139
+ ```typescript
140
+ // 문자열 enum
141
+ const FishEnum = z.enum(['Salmon', 'Tuna', 'Trout'])
142
+
143
+ FishEnum.parse('Salmon') // => "Salmon"
144
+ FishEnum.parse('Swordfish') // => ❌ throws
145
+
146
+ type Fish = z.infer<typeof FishEnum>
147
+ // 'Salmon' | 'Tuna' | 'Trout'
148
+
149
+ // Native enum
150
+ enum Fruits {
151
+ Apple,
152
+ Banana,
153
+ }
154
+ const FruitSchema = z.nativeEnum(Fruits)
155
+ ```
156
+
157
+ ## Record
158
+
159
+ ```typescript
160
+ const UserStore = z.record(z.string(), z.object({
161
+ name: z.string(),
162
+ }))
163
+
164
+ type UserStore = z.infer<typeof UserStore>
165
+ // { [key: string]: { name: string } }
166
+
167
+ // 사용
168
+ const userStore: UserStore = {}
169
+ userStore['77d2586b-9e8e-4ecf-8b21-ea7e0530eadd'] = {
170
+ name: 'Carlotta',
171
+ } // passes
172
+
173
+ userStore['77d2586b-9e8e-4ecf-8b21-ea7e0530eadd'] = {
174
+ whatever: 'Ice cream sundae',
175
+ } // TypeError
176
+ ```
177
+
178
+ ## Map & Set
179
+
180
+ ```typescript
181
+ // Map
182
+ const stringNumberMap = z.map(z.string(), z.number())
183
+ type StringNumberMap = z.infer<typeof stringNumberMap>
184
+ // Map<string, number>
185
+
186
+ // Set
187
+ const numberSet = z.set(z.number())
188
+ type NumberSet = z.infer<typeof numberSet>
189
+ // Set<number>
190
+ ```
191
+
192
+ ## 재귀 스키마 (JSON)
193
+
194
+ ```typescript
195
+ const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()])
196
+ type Literal = z.infer<typeof literalSchema>
197
+ type Json = Literal | { [key: string]: Json } | Json[]
198
+
199
+ const jsonSchema: z.ZodType<Json> = z.lazy(() =>
200
+ z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)])
201
+ )
202
+
203
+ jsonSchema.parse({ foo: [1, 2, { bar: 'baz' }] })
204
+ ```
@@ -0,0 +1,186 @@
1
+ # Zod
2
+
3
+ > **Version**: 4.x | TypeScript Schema Validation
4
+
5
+ ---
6
+
7
+ ## 🚀 Quick Reference (복사용)
8
+
9
+ ```typescript
10
+ // 기본 스키마
11
+ const schema = z.object({
12
+ email: z.email(), // v4 (string().email() 아님!)
13
+ name: z.string().min(1).trim(),
14
+ website: z.url().optional(), // v4 (string().url() 아님!)
15
+ age: z.number().int().positive(),
16
+ })
17
+
18
+ // 타입 추출
19
+ type Input = z.infer<typeof schema>
20
+
21
+ // 파싱
22
+ schema.parse(data) // 실패 시 throw
23
+ schema.safeParse(data) // { success, data/error }
24
+
25
+ // TanStack Start 연동
26
+ export const createUser = createServerFn({ method: 'POST' })
27
+ .inputValidator(schema)
28
+ .handler(async ({ data }) => prisma.user.create({ data }))
29
+ ```
30
+
31
+ ### v4 새 API (⚠️ 중요)
32
+
33
+ ```typescript
34
+ // ✅ v4 사용
35
+ z.email()
36
+ z.url()
37
+ z.uuid()
38
+ z.iso.date()
39
+ z.iso.datetime()
40
+
41
+ // ❌ v3 (deprecated)
42
+ z.string().email()
43
+ z.string().url()
44
+ ```
45
+
46
+ ---
47
+
48
+ ## 문서 구조
49
+
50
+ - [기본 타입](./basic-types.md) - 문자열, 숫자, 불리언, 날짜
51
+ - [복합 타입](./complex-types.md) - 객체, 배열, 튜플, 유니온, Enum
52
+ - [변환](./transforms.md) - Transform, Coerce, Preprocess
53
+ - [검증](./validation.md) - Refinement, Superrefine, 커스텀 검증
54
+
55
+ ## 빠른 시작
56
+
57
+ ```bash
58
+ yarn add zod
59
+ ```
60
+
61
+ ### 기본 사용법
62
+
63
+ ```typescript
64
+ import { z } from 'zod'
65
+
66
+ // 스키마 생성
67
+ const mySchema = z.string()
68
+
69
+ // parsing (실패 시 에러 throw)
70
+ mySchema.parse('tuna') // => "tuna"
71
+ mySchema.parse(12) // => throws ZodError
72
+
73
+ // safe parsing (에러를 던지지 않음)
74
+ mySchema.safeParse('tuna') // => { success: true; data: "tuna" }
75
+ mySchema.safeParse(12) // => { success: false; error: ZodError }
76
+ ```
77
+
78
+ ### 타입 추론
79
+
80
+ ```typescript
81
+ import { z } from 'zod'
82
+
83
+ const Player = z.object({
84
+ username: z.string(),
85
+ xp: z.number(),
86
+ })
87
+
88
+ // 스키마에서 타입 추출
89
+ type Player = z.infer<typeof Player>
90
+
91
+ // 타입 안전하게 사용
92
+ const player: Player = { username: 'billie', xp: 100 }
93
+ ```
94
+
95
+ ## v4 주요 변경사항
96
+
97
+ ### 에러 커스터마이징 통합
98
+
99
+ ```typescript
100
+ // v3 (deprecated)
101
+ z.string().min(5, { message: "Too short." })
102
+ z.string({ invalid_type_error: "Not a string", required_error: "Required" })
103
+
104
+ // v4 - error 파라미터로 통합
105
+ z.string().min(5, { error: "Too short." })
106
+ z.string({
107
+ error: (issue) => issue.input === undefined
108
+ ? "This field is required"
109
+ : "Not a string"
110
+ })
111
+ ```
112
+
113
+ ### 새로운 최상위 문자열 포맷 API
114
+
115
+ ```typescript
116
+ // v3 (deprecated)
117
+ z.string().email()
118
+ z.string().uuid()
119
+
120
+ // v4 - 최상위 API (더 나은 tree-shaking)
121
+ z.email()
122
+ z.uuid()
123
+ z.url()
124
+ z.base64()
125
+ z.nanoid()
126
+ z.cuid()
127
+ z.cuid2()
128
+ z.ulid()
129
+ z.ipv4()
130
+ z.ipv6()
131
+ z.iso.date()
132
+ z.iso.time()
133
+ z.iso.datetime()
134
+ ```
135
+
136
+ ### Strict/Loose 객체
137
+
138
+ ```typescript
139
+ // v3
140
+ z.object({ name: z.string() }).strict()
141
+ z.object({ name: z.string() }).passthrough()
142
+
143
+ // v4
144
+ z.strictObject({ name: z.string() })
145
+ z.looseObject({ name: z.string() })
146
+ ```
147
+
148
+ ### Refinements가 스키마 내부에 저장
149
+
150
+ ```typescript
151
+ // v3 - ZodEffects로 래핑되어 .min() 호출 불가
152
+ z.string()
153
+ .refine(val => val.includes("@"))
154
+ .min(5) // ❌ Property 'min' does not exist on type ZodEffects
155
+
156
+ // v4 - 스키마 내부에 저장되어 체이닝 가능
157
+ z.string()
158
+ .refine(val => val.includes("@"))
159
+ .min(5) // ✅
160
+ ```
161
+
162
+ ## TanStack Start와 함께 사용
163
+
164
+ ```typescript
165
+ import { createServerFn } from '@tanstack/react-start'
166
+ import { zodValidator } from '@tanstack/react-start/validators'
167
+ import { z } from 'zod'
168
+
169
+ const createUserSchema = z.object({
170
+ email: z.email(), // v4 새 API
171
+ name: z.string().min(1).max(100).trim(),
172
+ bio: z.string().max(500).optional(),
173
+ })
174
+
175
+ export const createUser = createServerFn({ method: 'POST' })
176
+ .inputValidator(zodValidator(createUserSchema))
177
+ .handler(async ({ data }) => {
178
+ // data는 타입 안전함
179
+ return prisma.user.create({ data })
180
+ })
181
+ ```
182
+
183
+ ## 참고 자료
184
+
185
+ - [Zod 공식 문서](https://zod.dev)
186
+ - [Zod GitHub](https://github.com/colinhacks/zod)
@@ -0,0 +1,174 @@
1
+ # Zod - 변환
2
+
3
+ > **상위 문서**: [Zod](./index.md)
4
+
5
+ ## Transform
6
+
7
+ 입력값을 다른 형태로 변환합니다.
8
+
9
+ ```typescript
10
+ const stringToLength = z.string().transform((val) => val.length)
11
+
12
+ stringToLength.parse('string') // => 6
13
+
14
+ type MySchemaIn = z.input<typeof stringToLength> // string
15
+ type MySchemaOut = z.output<typeof stringToLength> // number
16
+ ```
17
+
18
+ ### 체인으로 변환
19
+
20
+ ```typescript
21
+ const emailToLower = z.string()
22
+ .email()
23
+ .transform((email) => email.toLowerCase())
24
+
25
+ emailToLower.parse('User@Example.COM') // => "user@example.com"
26
+ ```
27
+
28
+ ## Pipe를 사용한 Transform
29
+
30
+ ```typescript
31
+ const stringToLength = z.string().pipe(z.transform(val => val.length))
32
+
33
+ stringToLength.parse('hello') // => 5
34
+ ```
35
+
36
+ ### 검증 후 변환
37
+
38
+ ```typescript
39
+ const stringToNumber = z.string()
40
+ .transform((val) => parseInt(val, 10))
41
+ .pipe(z.number().min(0).max(100))
42
+
43
+ stringToNumber.parse('50') // => 50
44
+ stringToNumber.parse('150') // => throws
45
+ ```
46
+
47
+ ## Transform 내에서 검증
48
+
49
+ ```typescript
50
+ const coercedInt = z.transform((val, ctx) => {
51
+ try {
52
+ const parsed = Number.parseInt(String(val))
53
+ return parsed
54
+ } catch (e) {
55
+ ctx.issues.push({
56
+ code: 'custom',
57
+ message: 'Not a number',
58
+ input: val,
59
+ })
60
+ return z.NEVER // 타입에 영향 없이 에러 반환
61
+ }
62
+ })
63
+ ```
64
+
65
+ ## Coerce (강제 변환)
66
+
67
+ 입력값을 자동으로 해당 타입으로 변환합니다.
68
+
69
+ ```typescript
70
+ z.coerce.string() // 모든 값을 문자열로
71
+ z.coerce.number() // 모든 값을 숫자로
72
+ z.coerce.boolean() // 모든 값을 불리언으로
73
+ z.coerce.date() // 모든 값을 날짜로
74
+ z.coerce.bigint() // 모든 값을 BigInt로
75
+ ```
76
+
77
+ ### v4 Coerce 입력 타입 변경
78
+
79
+ ```typescript
80
+ const schema = z.coerce.string()
81
+ type schemaInput = z.input<typeof schema>
82
+ // v3: string
83
+ // v4: unknown // ⚠️ 주의: 입력 타입이 unknown으로 변경됨
84
+ ```
85
+
86
+ ### Coerce 예시
87
+
88
+ ```typescript
89
+ // string coercion
90
+ z.coerce.string().parse(123) // => "123"
91
+ z.coerce.string().parse(true) // => "true"
92
+ z.coerce.string().parse(null) // => "null"
93
+
94
+ // number coercion
95
+ z.coerce.number().parse("42") // => 42
96
+ z.coerce.number().parse(true) // => 1
97
+ z.coerce.number().parse(false) // => 0
98
+
99
+ // boolean coercion
100
+ z.coerce.boolean().parse("true") // => true
101
+ z.coerce.boolean().parse("") // => false
102
+ z.coerce.boolean().parse(1) // => true
103
+
104
+ // date coercion
105
+ z.coerce.date().parse("2021-01-01") // => Date
106
+ z.coerce.date().parse(1609459200000) // => Date
107
+ ```
108
+
109
+ ### 환경변수 불리언 (v4 권장)
110
+
111
+ `z.coerce.boolean()` 대신 더 정교한 `z.stringbool()` 사용:
112
+
113
+ ```typescript
114
+ const strbool = z.stringbool()
115
+
116
+ strbool.parse("true") // => true
117
+ strbool.parse("yes") // => true
118
+ strbool.parse("1") // => true
119
+ strbool.parse("false") // => false
120
+ strbool.parse("no") // => false
121
+ strbool.parse("0") // => false
122
+ ```
123
+
124
+ ## Preprocess
125
+
126
+ 검증 전에 데이터를 전처리합니다.
127
+
128
+ ```typescript
129
+ const castToString = z.preprocess((val) => String(val), z.string())
130
+
131
+ castToString.parse(123) // => "123"
132
+ castToString.parse(null) // => "null"
133
+ ```
134
+
135
+ ### Preprocess vs Coerce
136
+
137
+ ```typescript
138
+ // preprocess - 커스텀 로직 가능
139
+ const trimmedString = z.preprocess(
140
+ (val) => typeof val === 'string' ? val.trim() : val,
141
+ z.string()
142
+ )
143
+
144
+ // coerce - 내장 변환만
145
+ const coercedString = z.coerce.string()
146
+ ```
147
+
148
+ ## 입력/출력 타입 분리
149
+
150
+ ```typescript
151
+ const Schema = z.object({
152
+ createdAt: z.string().transform((str) => new Date(str)),
153
+ })
154
+
155
+ type SchemaInput = z.input<typeof Schema>
156
+ // { createdAt: string }
157
+
158
+ type SchemaOutput = z.output<typeof Schema>
159
+ // { createdAt: Date }
160
+ ```
161
+
162
+ ## 조건부 변환
163
+
164
+ ```typescript
165
+ const conditionalTransform = z.string().transform((val) => {
166
+ if (val === 'null') return null
167
+ if (val === 'undefined') return undefined
168
+ return val
169
+ })
170
+
171
+ conditionalTransform.parse('hello') // => "hello"
172
+ conditionalTransform.parse('null') // => null
173
+ conditionalTransform.parse('undefined') // => undefined
174
+ ```