@kood/claude-code 0.1.5 → 0.1.7

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 (77) hide show
  1. package/dist/index.js +21 -243
  2. package/package.json +1 -1
  3. package/templates/hono/CLAUDE.md +10 -6
  4. package/templates/hono/docs/deployment/index.md +5 -0
  5. package/templates/hono/docs/library/hono/index.md +6 -0
  6. package/templates/hono/docs/library/prisma/index.md +3 -0
  7. package/templates/npx/CLAUDE.md +8 -2
  8. package/templates/tanstack-start/CLAUDE.md +105 -259
  9. package/templates/tanstack-start/docs/deployment/cloudflare.md +37 -424
  10. package/templates/tanstack-start/docs/deployment/index.md +57 -286
  11. package/templates/tanstack-start/docs/deployment/nitro.md +36 -318
  12. package/templates/tanstack-start/docs/deployment/railway.md +40 -409
  13. package/templates/tanstack-start/docs/deployment/vercel.md +43 -465
  14. package/templates/tanstack-start/docs/design/accessibility.md +56 -326
  15. package/templates/tanstack-start/docs/design/color.md +37 -179
  16. package/templates/tanstack-start/docs/design/components.md +77 -311
  17. package/templates/tanstack-start/docs/design/index.md +24 -87
  18. package/templates/tanstack-start/docs/design/safe-area.md +51 -250
  19. package/templates/tanstack-start/docs/design/spacing.md +57 -276
  20. package/templates/tanstack-start/docs/design/tailwind-setup.md +45 -359
  21. package/templates/tanstack-start/docs/design/typography.md +40 -284
  22. package/templates/tanstack-start/docs/guides/best-practices.md +3 -8
  23. package/templates/tanstack-start/docs/guides/env-setup.md +3 -3
  24. package/templates/tanstack-start/docs/library/better-auth/2fa.md +27 -115
  25. package/templates/tanstack-start/docs/library/better-auth/advanced.md +22 -105
  26. package/templates/tanstack-start/docs/library/better-auth/index.md +17 -66
  27. package/templates/tanstack-start/docs/library/better-auth/plugins.md +11 -88
  28. package/templates/tanstack-start/docs/library/better-auth/session.md +12 -92
  29. package/templates/tanstack-start/docs/library/better-auth/setup.md +9 -91
  30. package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +30 -358
  31. package/templates/tanstack-start/docs/library/prisma/config.md +27 -327
  32. package/templates/tanstack-start/docs/library/prisma/crud.md +46 -174
  33. package/templates/tanstack-start/docs/library/prisma/index.md +23 -113
  34. package/templates/tanstack-start/docs/library/prisma/relations.md +31 -153
  35. package/templates/tanstack-start/docs/library/prisma/schema.md +40 -217
  36. package/templates/tanstack-start/docs/library/prisma/setup.md +13 -113
  37. package/templates/tanstack-start/docs/library/prisma/transactions.md +20 -110
  38. package/templates/tanstack-start/docs/library/tanstack-query/index.md +12 -99
  39. package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +28 -107
  40. package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +44 -146
  41. package/templates/tanstack-start/docs/library/tanstack-query/setup.md +11 -73
  42. package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +33 -127
  43. package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +49 -149
  44. package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +19 -112
  45. package/templates/tanstack-start/docs/library/tanstack-start/index.md +33 -80
  46. package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +28 -106
  47. package/templates/tanstack-start/docs/library/tanstack-start/routing.md +21 -118
  48. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +41 -172
  49. package/templates/tanstack-start/docs/library/tanstack-start/setup.md +6 -39
  50. package/templates/tanstack-start/docs/library/zod/basic-types.md +33 -145
  51. package/templates/tanstack-start/docs/library/zod/complex-types.md +32 -156
  52. package/templates/tanstack-start/docs/library/zod/index.md +22 -150
  53. package/templates/tanstack-start/docs/library/zod/transforms.md +20 -129
  54. package/templates/tanstack-start/docs/library/zod/validation.md +39 -155
  55. package/templates/hono/docs/commands/git.md +0 -145
  56. package/templates/hono/docs/mcp/context7.md +0 -106
  57. package/templates/hono/docs/mcp/index.md +0 -176
  58. package/templates/hono/docs/mcp/sequential-thinking.md +0 -101
  59. package/templates/hono/docs/mcp/serena.md +0 -269
  60. package/templates/hono/docs/mcp/sgrep.md +0 -105
  61. package/templates/hono/docs/skills/gemini-review/SKILL.md +0 -220
  62. package/templates/hono/docs/skills/gemini-review/references/checklists.md +0 -136
  63. package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +0 -303
  64. package/templates/npx/docs/commands/git.md +0 -145
  65. package/templates/npx/docs/mcp/index.md +0 -60
  66. package/templates/npx/docs/skills/gemini-review/SKILL.md +0 -220
  67. package/templates/npx/docs/skills/gemini-review/references/checklists.md +0 -134
  68. package/templates/npx/docs/skills/gemini-review/references/prompt-templates.md +0 -301
  69. package/templates/tanstack-start/docs/commands/git.md +0 -145
  70. package/templates/tanstack-start/docs/mcp/context7.md +0 -204
  71. package/templates/tanstack-start/docs/mcp/index.md +0 -177
  72. package/templates/tanstack-start/docs/mcp/sequential-thinking.md +0 -180
  73. package/templates/tanstack-start/docs/mcp/serena.md +0 -269
  74. package/templates/tanstack-start/docs/mcp/sgrep.md +0 -174
  75. package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +0 -220
  76. package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +0 -144
  77. package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +0 -292
@@ -1,186 +1,74 @@
1
1
  # Zod - 기본 타입
2
2
 
3
- > **상위 문서**: [Zod](./index.md)
4
-
5
3
  ## 문자열
6
4
 
7
5
  ```typescript
8
6
  z.string()
9
- z.string().min(1) // 최소 길이
10
- z.string().max(100) // 최대 길이
11
- z.string().length(5) // 정확한 길이
12
- z.string().regex(/^\d+$/) // 정규식
13
- z.string().trim() // 공백 제거
14
- z.string().toLowerCase() // 소문자 변환
15
- z.string().toUpperCase() // 대문자 변환
7
+ z.string().min(1).max(100).length(5)
8
+ z.string().regex(/^\d+$/)
9
+ z.string().trim().toLowerCase().toUpperCase()
16
10
  ```
17
11
 
18
- ### v4 새로운 최상위 문자열 포맷 API
12
+ ### v4 최상위 포맷 API
19
13
 
20
14
  ```typescript
21
- // 더 나은 tree-shaking을 위해 최상위 API 사용 권장
22
- z.email() // 이메일 형식
23
- z.url() // URL 형식
24
- z.uuid() // UUID 형식
25
- z.base64() // Base64 형식
26
- z.base64url() // Base64 URL 형식
27
- z.nanoid() // NanoID 형식
28
- z.cuid() // CUID 형식
29
- z.cuid2() // CUID2 형식
30
- z.ulid() // ULID 형식
31
- z.emoji() // 이모지 (단일 문자)
32
- z.ipv4() // IPv4 주소
33
- z.ipv6() // IPv6 주소
34
- z.cidrv4() // IPv4 범위
35
- z.cidrv6() // IPv6 범위
36
-
37
- // ISO 날짜/시간 형식
38
- z.iso.date() // ISO 날짜 (2024-01-15)
39
- z.iso.time() // ISO 시간 (14:30:00)
40
- z.iso.datetime() // ISO 날짜시간
41
- z.iso.duration() // ISO 기간 (P1D, PT1H)
15
+ z.email() z.url() z.uuid() z.base64()
16
+ z.nanoid() z.cuid() z.cuid2() z.ulid()
17
+ z.ipv4() z.ipv6() z.cidrv4() z.cidrv6()
18
+
19
+ z.iso.date() // 2024-01-15
20
+ z.iso.time() // 14:30:00
21
+ z.iso.datetime() // ISO 날짜시간
22
+ z.iso.duration() // P1D, PT1H
42
23
  ```
43
24
 
44
- ### 템플릿 리터럴 타입 (v4 신규)
25
+ ### 템플릿 리터럴 (v4)
45
26
 
46
27
  ```typescript
47
- const hello = z.templateLiteral(["hello, ", z.string()])
48
- // `hello, ${string}`
49
-
50
- const cssUnits = z.enum(["px", "em", "rem", "%"])
51
- const css = z.templateLiteral([z.number(), cssUnits])
52
- // `${number}px` | `${number}em` | `${number}rem` | `${number}%`
53
-
54
- const email = z.templateLiteral([
55
- z.string().min(1),
56
- "@",
57
- z.string().max(64),
58
- ])
59
- // `${string}@${string}` (min/max refinements도 적용됨!)
28
+ const css = z.templateLiteral([z.number(), z.enum(["px", "em", "rem"])])
29
+ // `${number}px` | `${number}em` | `${number}rem`
60
30
  ```
61
31
 
62
32
  ## 숫자
63
33
 
64
34
  ```typescript
65
35
  z.number()
66
- z.number().min(0) // 최솟값
67
- z.number().max(100) // 최댓값
68
- z.number().int() // 정수만
69
- z.number().positive() // 양수만
70
- z.number().negative() // 음수만
71
- z.number().nonnegative() // 0 이상
72
- z.number().nonpositive() // 0 이하
73
- z.number().finite() // 유한 숫자
74
- z.number().safe() // 안전한 정수 범위
36
+ z.number().min(0).max(100).int()
37
+ z.number().positive().negative().nonnegative().nonpositive()
38
+ z.number().finite().safe()
75
39
  ```
76
40
 
77
41
  ## 불리언
78
42
 
79
43
  ```typescript
80
44
  z.boolean()
81
- ```
82
-
83
- ### 문자열 불리언 (v4 신규)
84
-
85
- 환경변수 스타일 불리언 변환:
86
-
87
- ```typescript
88
- const strbool = z.stringbool()
89
-
90
- strbool.parse("true") // => true
91
- strbool.parse("1") // => true
92
- strbool.parse("yes") // => true
93
- strbool.parse("on") // => true
94
- strbool.parse("enabled") // => true
95
-
96
- strbool.parse("false") // => false
97
- strbool.parse("0") // => false
98
- strbool.parse("no") // => false
99
- strbool.parse("off") // => false
100
- strbool.parse("disabled") // => false
101
-
102
- // 커스텀 truthy/falsy 값
103
- z.stringbool({
104
- truthy: ["yes", "true"],
105
- falsy: ["no", "false"]
106
- })
107
- ```
108
-
109
- ## 날짜
110
-
111
- ```typescript
112
- z.date()
113
- z.date().min(new Date('2020-01-01'))
114
- z.date().max(new Date('2030-12-31'))
115
- ```
116
-
117
- ## BigInt
118
-
119
- ```typescript
120
- z.bigint()
121
- z.bigint().positive()
122
- z.bigint().negative()
123
- ```
124
-
125
- ## 리터럴
126
-
127
- ```typescript
128
- z.literal('hello') // 정확히 'hello'만
129
- z.literal(42) // 정확히 42만
130
- z.literal(true) // 정확히 true만
131
- ```
132
-
133
- ## Null, Undefined, Void
134
-
135
- ```typescript
136
- z.null() // null만 허용
137
- z.undefined() // undefined만 허용
138
- z.void() // undefined 허용 (반환 타입용)
139
- ```
140
45
 
141
- ## Any, Unknown, Never
142
-
143
- ```typescript
144
- z.any() // 모든 타입 허용
145
- z.unknown() // unknown 타입
146
- z.never() // 값 없음 (유니온에서 사용)
46
+ // v4 문자열 불리언 (환경변수용)
47
+ z.stringbool() // "true"/"yes"/"1" → true, "false"/"no"/"0" → false
147
48
  ```
148
49
 
149
- > **v4 변경**: `z.any()`와 `z.unknown()`은 더 이상 객체에서 선택적 키로 추론되지 않습니다.
150
- > ```typescript
151
- > const mySchema = z.object({ a: z.any(), b: z.unknown() })
152
- > // v3: { a?: any; b?: unknown }
153
- > // v4: { a: any; b: unknown }
154
- > ```
155
-
156
- ## Optional & Nullable
50
+ ## 날짜/BigInt/리터럴
157
51
 
158
52
  ```typescript
159
- z.string().optional() // string | undefined
160
- z.string().nullable() // string | null
161
- z.string().nullish() // string | null | undefined
53
+ z.date().min(new Date('2020-01-01')).max(new Date('2030-12-31'))
54
+ z.bigint().positive().negative()
55
+ z.literal('hello') z.literal(42) z.literal(true)
162
56
  ```
163
57
 
164
- ## Default
58
+ ## 특수 타입
165
59
 
166
60
  ```typescript
167
- const Schema = z.object({
168
- name: z.string().default('Anonymous'),
169
- role: z.enum(['admin', 'user']).default('user'),
170
- })
171
-
172
- Schema.parse({}) // { name: 'Anonymous', role: 'user' }
61
+ z.null() z.undefined() z.void()
62
+ z.any() z.unknown() z.never()
173
63
  ```
174
64
 
175
- ## 타입 추론
65
+ ## 수정자
176
66
 
177
67
  ```typescript
178
- const stringSchema = z.string()
179
- type StringType = z.infer<typeof stringSchema> // string
180
-
181
- const numberSchema = z.number().optional()
182
- type NumberType = z.infer<typeof numberSchema> // number | undefined
68
+ z.string().optional() // string | undefined
69
+ z.string().nullable() // string | null
70
+ z.string().nullish() // string | null | undefined
71
+ z.string().default('Anonymous')
183
72
 
184
- const dateSchema = z.date().nullable()
185
- type DateType = z.infer<typeof dateSchema> // Date | null
73
+ type T = z.infer<typeof schema>
186
74
  ```
@@ -1,204 +1,80 @@
1
1
  # Zod - 복합 타입
2
2
 
3
- > **상위 문서**: [Zod](./index.md)
4
-
5
3
  ## 객체
6
4
 
7
5
  ```typescript
8
6
  const UserSchema = z.object({
9
7
  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']),
8
+ email: z.email(),
9
+ age: z.number().optional(),
48
10
  })
49
11
 
50
- // 병합
51
- const MergedSchema = UserSchema.merge(AnotherSchema)
52
- ```
53
-
54
- ### Strict/Loose 객체 (v4)
12
+ // 메서드
13
+ UserSchema.partial() // 모든 필드 optional
14
+ UserSchema.required() // 모든 필드 required
15
+ UserSchema.pick({ name: true }) // 특정 필드만
16
+ UserSchema.omit({ email: true }) // 특정 필드 제외
17
+ UserSchema.extend({ role: z.enum(['admin', 'user']) })
18
+ UserSchema.merge(AnotherSchema)
55
19
 
56
- ```typescript
57
- // v3
58
- z.object({ name: z.string() }).strict() // 추가 키 에러
59
- z.object({ name: z.string() }).passthrough() // 추가 키 통과
60
-
61
- // v4 - 새로운 API
20
+ // v4 Strict/Loose
62
21
  z.strictObject({ name: z.string() }) // 추가 키 에러
63
22
  z.looseObject({ name: z.string() }) // 추가 키 통과
64
23
  ```
65
24
 
66
- ## 배열
25
+ ## 배열/튜플
67
26
 
68
27
  ```typescript
69
28
  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
- ```
29
+ z.array(z.number()).min(1).max(10).length(5).nonempty()
75
30
 
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]
31
+ z.tuple([z.string(), z.number()]) // [string, number]
86
32
  ```
87
33
 
88
34
  ## 유니온
89
35
 
90
36
  ```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
- ```
37
+ z.union([z.string(), z.number()])
38
+ z.string().or(z.number())
98
39
 
99
- ## Discriminated Union
100
-
101
- ```typescript
102
- const Shape = z.discriminatedUnion('type', [
40
+ // Discriminated Union
41
+ z.discriminatedUnion('type', [
103
42
  z.object({ type: z.literal('circle'), radius: z.number() }),
104
43
  z.object({ type: z.literal('rectangle'), width: z.number(), height: z.number() }),
105
44
  ])
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
45
  ```
136
46
 
137
47
  ## Enum
138
48
 
139
49
  ```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'
50
+ const Status = z.enum(['pending', 'done', 'cancelled'])
51
+ type Status = z.infer<typeof Status> // 'pending' | 'done' | 'cancelled'
148
52
 
149
53
  // Native enum
150
- enum Fruits {
151
- Apple,
152
- Banana,
153
- }
154
- const FruitSchema = z.nativeEnum(Fruits)
54
+ enum Fruits { Apple, Banana }
55
+ z.nativeEnum(Fruits)
155
56
  ```
156
57
 
157
- ## Record
58
+ ## Record/Map/Set
158
59
 
159
60
  ```typescript
160
- const UserStore = z.record(z.string(), z.object({
161
- name: z.string(),
162
- }))
163
-
164
- type UserStore = z.infer<typeof UserStore>
61
+ z.record(z.string(), z.object({ name: z.string() }))
165
62
  // { [key: string]: { name: string } }
166
63
 
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
64
+ z.map(z.string(), z.number()) // Map<string, number>
65
+ z.set(z.number()) // Set<number>
176
66
  ```
177
67
 
178
- ## Map & Set
68
+ ## 재귀 스키마
179
69
 
180
70
  ```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[]
71
+ type Json = string | number | boolean | null | { [key: string]: Json } | Json[]
198
72
 
199
73
  const jsonSchema: z.ZodType<Json> = z.lazy(() =>
200
- z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)])
74
+ z.union([
75
+ z.string(), z.number(), z.boolean(), z.null(),
76
+ z.array(jsonSchema),
77
+ z.record(jsonSchema)
78
+ ])
201
79
  )
202
-
203
- jsonSchema.parse({ foo: [1, 2, { bar: 'baz' }] })
204
80
  ```
@@ -1,21 +1,25 @@
1
1
  # Zod
2
2
 
3
- > **Version**: 4.x | TypeScript Schema Validation
3
+ > **v4** | TypeScript Schema Validation
4
+
5
+ @basic-types.md
6
+ @complex-types.md
7
+ @transforms.md
8
+ @validation.md
4
9
 
5
10
  ---
6
11
 
7
- ## 🚀 Quick Reference (복사용)
12
+ ## Quick Reference
8
13
 
9
14
  ```typescript
10
15
  // 기본 스키마
11
16
  const schema = z.object({
12
- email: z.email(), // v4 (string().email() 아님!)
17
+ email: z.email(), // v4! (string().email() 아님)
13
18
  name: z.string().min(1).trim(),
14
- website: z.url().optional(), // v4 (string().url() 아님!)
19
+ website: z.url().optional(), // v4! (string().url() 아님)
15
20
  age: z.number().int().positive(),
16
21
  })
17
22
 
18
- // 타입 추출
19
23
  type Input = z.infer<typeof schema>
20
24
 
21
25
  // 파싱
@@ -28,159 +32,27 @@ export const createUser = createServerFn({ method: 'POST' })
28
32
  .handler(async ({ data }) => prisma.user.create({ data }))
29
33
  ```
30
34
 
31
- ### v4 새 API (⚠️ 중요)
35
+ ### ⚠️ v4 새 API
32
36
 
33
37
  ```typescript
34
- // ✅ v4 사용
35
- z.email()
36
- z.url()
37
- z.uuid()
38
- z.iso.date()
39
- z.iso.datetime()
38
+ // ✅ v4
39
+ z.email() z.url() z.uuid()
40
+ z.iso.date() z.iso.datetime()
40
41
 
41
- // ❌ v3 (deprecated)
42
- z.string().email()
43
- z.string().url()
42
+ // ❌ v3 deprecated
43
+ z.string().email() z.string().url()
44
44
  ```
45
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
- ### 기본 사용법
46
+ ### v4 주요 변경
62
47
 
63
48
  ```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 파라미터로 통합
49
+ // 에러 커스텀: message error
105
50
  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
51
 
148
- ### Refinements가 스키마 내부에 저장
52
+ // Strict/Loose 객체
53
+ z.strictObject({ name: z.string() }) // 추가 키 에러
54
+ z.looseObject({ name: z.string() }) // 추가 키 통과
149
55
 
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
- })
56
+ // Refinement 체이닝 가능
57
+ z.string().refine(val => val.includes("@")).min(5) // v4
181
58
  ```
182
-
183
- ## 참고 자료
184
-
185
- - [Zod 공식 문서](https://zod.dev)
186
- - [Zod GitHub](https://github.com/colinhacks/zod)