Phát hành Zod 4
(zod.dev)- Zod, thư viện khai báo schema và xác thực dữ liệu, đã phát hành phiên bản 4 ổn định với nhiều cải thiện hiệu năng lớn và các tính năng được yêu cầu từ lâu
- Có cải tiến đáng kể về tốc độ và kích thước bundle, đồng thời phiên bản mini mới (v4-mini) giúp giảm mạnh kích thước bundle
- Bổ sung registry metadata mới, chuyển đổi sang JSON Schema, cùng khả năng suy luận kiểu đệ quy
- Trải nghiệm lập trình viên được nâng cao với tùy biến thông báo lỗi và hệ thống locale đa ngôn ngữ
- Khả năng mở rộng tiếp tục được tăng cường với việc giới thiệu gói con core có thể dùng để xây dựng thư viện trong tương lai
Giới thiệu Zod 4
Thông tin về bản phát hành chính
- Sau 1 năm phát triển tích cực, Zod 4 đã được phát hành ở phiên bản ổn định
- Quá trình phát triển nhận được hỗ trợ từ OSS Fellowship của Clerk
- Hiện được phát hành song song với Zod 3, giúp việc di chuyển dần sang Zod 4 trở nên dễ dàng hơn
- Có thể xem hướng dẫn chi tiết về một số thay đổi mang tính phá vỡ tại Migration guide
Bối cảnh tăng trưởng
- So với Zod 3 ra mắt năm 2021, Zod 4 đã tăng trưởng theo cấp số nhân về số sao GitHub và lượt tải hàng tuần
- Zod 4 nhanh hơn nhiều, gọn hơn và hiệu quả hơn với trình biên dịch TypeScript
- 9 vấn đề lớn được yêu cầu từ lâu đã được giải quyết
Benchmark và hiệu năng
- Cải thiện tốc độ:
- Phân tích chuỗi: nhanh hơn 14,71 lần
- Phân tích mảng: nhanh hơn 7,43 lần
- Phân tích đối tượng (
safeParse): nhanh hơn 6,5 lần
- Cung cấp script để có thể tự chạy benchmark trực tiếp từ repo
- Nhờ cấu trúc generic được cải tiến, hiệu năng biên dịch khi chain các phương thức như
.extend(),.omit()được cải thiện gấp 10 lần - Tốc độ biên dịch TypeScript được cải thiện đáng kể trong các schema và codebase quy mô lớn
Kích thước bundle và Zod Mini
- Kích thước bundle cơ bản giảm 57%, giúp v4 nhỏ hơn v3 khoảng 2,3 lần
- zod/v4-mini cung cấp API dạng hàm có thể tree-shake, giúp giảm kích thước bundle tới 85%
- Sự khác biệt API giữa core và v4-mini được tổng hợp chi tiết trong tài liệu chính thức
- Cấu trúc được thiết kế để bundler có thể dễ dàng loại bỏ các phương thức không sử dụng
Registry metadata và hỗ trợ JSON Schema
- Có thể đăng ký và quản lý typed metadata trên schema với kiểu mạnh
- Registry toàn cục (
z.globalRegistry) cung cấp khả năng xử lý metadata tương thích JSON Schema và tự động đưa vào - Dễ dàng tài liệu hóa schema thông qua
.meta(),.describe() - Với
.toJSONSchema(), có thể chuyển schema sang định dạng JSON Schema và tự động phản ánh metadata
Tự động suy luận kiểu đệ quy
- Có thể định nghĩa và suy luận tự nhiên các kiểu đối tượng đệ quy và kiểu đệ quy lẫn nhau mà không cần ép kiểu riêng
- Tính dễ dùng được cải thiện đáng kể so với mẫu Zod 3 trước đây
- Ngay cả với kiểu đệ quy/đệ quy lẫn nhau, mọi phương thức schema vẫn có thể được sử dụng
Kiểu file và tính năng xác thực
- Kiểu
file()mới cho phép xác thực các instanceFile - Cung cấp xác thực nhiều ràng buộc file như kích thước file (
min,max) và MIME type
Thông báo lỗi và hệ thống locale
- API locale toàn cục (
z.locales) cho phép hỗ trợ đa ngôn ngữ cho thông báo lỗi - Hàm chính thức
z.prettifyErrorhỗ trợ định dạng lỗi thân thiện với người dùng
Hàm format và template literal
- Các format chuỗi hiện có (
emailv.v.) được nâng lên thành hàm cấp cao hơn, cải thiện khả năng đọc và tree shaking - Cung cấp nhiều tùy chọn regex email để đáp ứng các nhu cầu xác thực khác nhau
- Hỗ trợ kiểu template literal: dễ dàng triển khai các mẫu chuỗi và tổ hợp phức tạp có thể biểu diễn trong hệ thống kiểu
Các format số và bigint mới được bổ sung
- Hỗ trợ kiểu số nguyên và số thực có độ rộng cố định (
int32,uint64v.v.) - Có thể tạo schema tự động được thêm ràng buộc tối thiểu/tối đa trong phạm vi an toàn
Giới thiệu z.stringbool
- Có thể parse boolean từ chuỗi (
yes,nov.v.), đồng thời hỗ trợ kiểu parse theo phong cách biến môi trường - Có thể tùy biến các giá trị truthy/falsy
Hợp nhất API tùy biến lỗi
- Thông qua tham số
errorđược hợp nhất, cấu trúc thông báo lỗi và logic xử lý trở nên gọn gàng hơn - Các API liên quan đến lỗi trước đây (
message,invalid_type_error,errorMap) đã bị deprecated
Các cải tiến cốt lõi khác
- Discriminated unions hỗ trợ nhiều schema, lồng nhau và tổ hợp
.literal()có thể cho phép nhiều giá trị cùng lúc- Xác thực tùy chỉnh như
.refine()được tích hợp trực quan hơn - Với
.overwrite()liên quan đến transform, có thể hậu xử lý mà không thay đổi kiểu transform
Khả năng mở rộng thư viện và core mới
- Với zod/v4/core, các chức năng cốt lõi được tách thành gói con riêng, cho phép tích hợp/mở rộng với nhiều thư viện và nền tảng khác nhau
- Cung cấp tài liệu hướng dẫn và ví dụ mở rộng dành cho người tạo thư viện
Kết luận
- Zod 4 trở thành thư viện xác thực dữ liệu cải thiện mạnh mẽ cả độ an toàn kiểu, hiệu năng, khả năng mở rộng và trải nghiệm lập trình viên
- Các bài viết thiết kế và bản cập nhật tiếp theo đã được báo trước
- Đang chuẩn bị hỗ trợ rộng rãi cho cả người dùng hiện tại lẫn người tạo thư viện
Chúc bạn có trải nghiệm parse thật vui vẻ
— Colin McDonnell @colinhacks
1 bình luận
Ý kiến Hacker News
Tác giả bài viết đề nghị mọi người chia sẻ quan điểm cá nhân và giải thích chi tiết về cách quản lý phiên bản, nhấn mạnh rằng npm không phù hợp để xử lý tình huống như của Zod, đồng thời nhắc đến việc rất nhiều thư viện nhập trực tiếp và sử dụng interface/class của Zod; nếu Zod thay đổi major version thì tất cả các thư viện đó sẽ phải đồng loạt thích ứng, dễ dẫn tới hiện tượng bùng nổ phiên bản. Anh cũng nói rằng, tương tự Go, với các thay đổi phá vỡ tương thích thì nên dùng cách thêm đường dẫn subpath mới, và trong môi trường TypeScript có thể hỗ trợ đồng thời cả
"zod/v3"và"zod/v4"chỉ vớizod@^3.25.0, từ đó cung cấp lộ trình nâng cấp dần cho người dùng cuối.Cảm ơn vì những đóng góp cho Zod, đặc biệt bày tỏ kỳ vọng vào việc cải thiện hiệu năng của
tscvà discriminated unions. Dù hiểu đầy đủ cách quản lý phiên bản, người này vẫn đề xuất rằng với những người dùng như họ, vốn không lo xung đột phụ thuộc bắc cầu, có lẽ cũng nên phát hành riêng dưới dạng gói 4.0.0. Họ cho rằng việc phải đổi import sang"zod/v4"sẽ tạo thêm nhiễu trong mã và gây thêm phiền toái như xung đột với auto import của IDE. Tuy vậy, nhìn chung đây vẫn là một bản nâng cấp rất hứa hẹn và họ gửi lời cảm ơn.Người này nói đang xem bài trên di động nên xin bỏ qua nếu đã bỏ sót, rồi hỏi liệu điểm khó chịu lớn nhất liên quan đến
.optional()có nằm trong nhóm top issue 9/10 đã được giải quyết lần này hay chưa. Họ nói Zod quá xuất sắc nên dù có chút bất tiện vẫn tiếp tục dùng, và cảm ơn vì đây là một thư viện tuyệt vời.Cảm ơn vì trong phiên bản mới của Zod có thể loại bỏ được rất nhiều mã hack thủ công. Người này cho biết bản thân đang dùng
zod-key-parserđể giảm lỗi gõ sai, và thắc mắc vì sao tính năng như vậy chưa được tích hợp sẵn trong thư viện, là vì bị xem là ngoài phạm vi hay chỉ là chưa được triển khai, đồng thời chia sẻ các thảo luận mở có liên quan.Nhấn mạnh rằng cách giảm thiểu nỗi đau ngắn hạn đôi khi thường là cách tốt nhất, và nhắc lại ký ức về sự hỗn loạn lớn trong quá trình migrate Python 2/3.
Chia sẻ từng gặp khó khăn đáng kể khi phải dùng đồng thời recursive type và discriminated union, ví dụ như nhúng XML vào trong JSON, và hy vọng bản cập nhật lần này sẽ cải thiện tình hình nhiều.
Bày tỏ sự nghi ngại với import
zod/v4-mini, đoán rằng điều này ngược lại có thể làm tăng kích thước bundle. Vì tài liệu chính thức nói rằng"zod/v4"được khuyến nghị trong hầu hết trường hợp nên lập trình viên ứng dụng sẽ dùngzod/v4, nhưng nếu tác giả thư viện thêm cảzod/v4-miniđể giảm bundle size thì có nguy cơ cả hai cùng bị đưa vào bundle và gây trùng lặp. Họ hỏi liệu nếuzod/v4chỉ là wrapper củazod/v4-minithì có thể giảm vấn đề này hay không.Để giúp việc migrate sang Zod 4 dễ hơn, nhóm đã đưa ra cách cung cấp đồng thời v3 và v4 trong
zod@3.25; có ý kiến chỉ trích rằng cấu trúc này, kết hợp với giới hạn trong cách npm quản lý dependency, đã khiến v4 phải trông giống như v3, và chỉ ra sự kém hiệu quả trong hệ thống peer dependencies của npm.Tác giả bài viết giải thích lại chiến lược quản lý phiên bản kiểu Golang bằng cách thêm subpath, nhấn mạnh rằng dù khó triển khai trong hệ sinh thái Zod vì đặc tính của npm, cách này vẫn có ưu điểm là hỗ trợ đồng thời v3 và v4 cũng như cho phép migrate dần dần.
Không hoàn toàn đồng ý với nhận xét trước đó rằng vì peer dependencies bị hỏng nên phải cải trang v4 thành v3; người này nhấn mạnh đây là biện pháp để migrate dần dần, theo kiểu thay thế từng phần sang
'zod/v4'rồi cuối cùng nâng cấp hoàn toàn lên v4.Dù nhiều người đang chỉ trích, người này nhấn mạnh đây không hẳn là giới hạn bản chất của npm, mà là một quyết định thực dụng để cho phép chuyển đổi dần một thư viện có thay đổi lớn.
Có thể vì đã dùng npm quá lâu nên có thiên kiến, nhưng người này nói họ tò mò không biết còn cách nào tốt hơn để hỗ trợ dần từ v3 sang v4 thay vì bắt mọi người chuyển toàn bộ một lần.
Dù đã thấy nhiều cải thiện lớn từ bản beta Zod 4, người này vẫn chưa thể nâng cấp đúng cách trong codebase lớn vì cấu hình module resolution quá khó. Họ nói mong muốn nó cũng được phát hành đơn thuần dưới dạng major version, không có lớp legacy, rồi chia sẻ phần giải thích của tác giả về việc tránh “bùng nổ phiên bản”. Tuy vậy, bản thân họ nghĩ rằng nếu vẫn duy trì hỗ trợ v3 song song thì cú sốc có thể được làm dịu đi.
Hỏi rằng trong các trường hợp phức tạp như kiểu dữ liệu server trả về khác nhau theo từng endpoint, hoặc có một số field đôi khi là
nullnhư với người dùng ẩn danh, thì nên mô hình hóa response của server bằng loại type nào. Người này nói rằng khi tạo nhiều hàm nhưnormalizeUser/normalizePostthì việc quản lý ngày càng phức tạp, và muốn nghe chia sẻ kinh nghiệm thực tế về cách giải quyết vấn đề này.Đưa ra cách giải quyết bằng ví dụ discriminated union: định nghĩa phần schema chung thành object rồi mở rộng theo từng tình huống cụ thể. Họ khuyên rằng với những trường hợp quá đa dạng thì mọi thứ vốn dĩ vẫn có thể phức tạp, nhưng ít nhất schema validator giúp duy trì cấu trúc có hệ thống hơn.
Lý tưởng nhất là xác định cấu trúc type của User từ một nguồn duy nhất, ví dụ dưới dạng discriminated union. Nếu backend là Python thì có thể dùng nhiều model Pydantic + union, rồi dùng code generation từ OpenAPI/GraphQL để tạo type client TypeScript.
Nói rằng nếu biết ví dụ sử dụng thực tế thì có thể trả lời tốt hơn, nhưng giải thích rằng nếu thêm một thuộc tính phân biệt vào union type, ví dụ
"user_type", thì việc truy cập field riêng của từng loại sẽ dễ hơn, và hệ thống type có thể nhận biết đúng thuộc tính cho từng tình huống.Khuyên mạnh rằng server nên trực tiếp xuất type. Việc viết lại riêng từng type ở phía client là không hiệu quả; với backend Python có thể dùng Pydantic để tự động sinh OpenAPI spec rồi tạo type cho client TypeScript.
Nêu rằng GraphQL được thiết kế phù hợp cho kiểu trường hợp này; các thư viện GraphQL cho TypeScript có thể tự động suy luận hình dạng kết quả truy vấn, và sinh type response linh hoạt theo đúng các field đã chọn.
Nhắc rằng dù Zod 4 đã cải thiện, ArkType vẫn nhanh hơn hẳn. Với các thư viện đã tồn tại, việc phải giữ tương thích ngược và duy trì cú pháp khiến hiệu năng bị giới hạn; theo phân tích của người này trong dự án của họ, đó là lý do họ chọn ArkType, cả vì hiệu năng lẫn trải nghiệm dùng TypeScript.
Nói rằng đã xem các chỉ số tốc độ của ArkType, nhưng tò mò không biết tốc độ đó thực tế tác động thế nào đến việc sử dụng. Trong các tình huống bình thường như validate form thì có vẻ ảnh hưởng không nhiều, nên họ tự hỏi liệu nó có chủ yếu được dùng ở các nơi nhạy cảm hiệu năng như validate input cho API siêu nhanh hay không.
ArkType không có trong nghiên cứu được nhắc đến, nhưng người này nói họ cũng từng tìm hiểu nó vì trải nghiệm TypeScript; dù vậy họ không có kế hoạch rời Zod.
Chia sẻ rằng trải nghiệm dùng ArkType rất khó khăn, còn Zod thì dễ dùng hơn nên họ thích Zod hơn.
Hỏi lý do cụ thể vì sao chọn ArkType thay vì TypeBox.
Chúc mừng bản phát hành mới của đội ngũ Zod, nhưng lo ngại rằng nhìn vào số lượng thay đổi phá vỡ tương thích trong migration guide thì các dự án lớn phụ thuộc nhiều vào Zod sẽ thấy rất nặng nề và khó quản lý. Dựa trên kinh nghiệm duy trì các dự án frontend cũ, người này bày tỏ sự tiếc nuối với xu hướng phát triển hiện tại của JS khi mỗi thư viện đều có thay đổi lớn và tài liệu thường không đầy đủ.
Người này nói họ đang vận hành nhiều ứng dụng Next.js lớn, và trong một năm gần đây đã phải trải qua các thay đổi lớn, khó khăn như Next.js 14→15, Next.js pages→app router, React 18→19, Eslint 8→9, Tailwind 3→4, nên thực sự rất mệt mỏi và thậm chí từng nghĩ giá mà xây bằng Django thì tốt hơn. Họ hồi tưởng rằng riêng migration Tailwind 3→4 lại bất ngờ là phần đau đớn nhất.
Giải thích rằng để giảm bớt vấn đề này, nhóm đã áp dụng chiến lược phát hành song song bản
'mini', giúp việc chuyển đổi dần dễ hơn, và việc đưa ra'mini'cũng là điều khó tránh nếu xét tới tối ưu tree-shaking và nhu cầu cạnh tranh với các lựa chọn thay thế.Đề xuất rằng có thể tận dụng các công cụ như LLM để migrate mà không quá khó khăn.
Nói rằng Zod vượt trội hơn rất nhiều so với các lựa chọn cũ khác, nhưng trong phát triển web, thực tế vẫn là phải mô tả cùng một cấu trúc dữ liệu theo nhiều cách khác nhau: validate input JS, đặc tả API qua Swagger, định nghĩa riêng ở server và client, v.v., quá lặp lại và phiền phức.
Bày tỏ tiếc nuối rằng TypeScript vẫn giữ lập trường chỉ là công cụ kiểm tra tĩnh; không hẳn muốn runtime check, nhưng mong dữ liệu type của class/hàm/object có thể dễ dàng được dùng ra bên ngoài. Hiện tại nhiều công cụ đều phải tự định nghĩa model và builder riêng nên sự trùng lặp là khó tránh. Người này chia sẻ rằng dự án Standard Schema, một nỗ lực chuẩn hóa, có dấu hiệu tích hợp với các thư viện validator lớn, nhưng việc mở rộng sang đặc tả API và ORM vẫn còn ở giai đoạn đầu.
Nhấn mạnh rằng điểm cốt lõi của các công cụ kiểu này là chỉ cần định nghĩa một lần rồi lan truyền type safety ra toàn bộ ứng dụng; có thể xem schema Zod như một single source of truth.
Cũng nói thêm rằng trong số những người thấy cấu trúc rườm rà này khó chịu, có nhiều người lại phản đối cả đề xuất gom mọi thứ về một hệ duy nhất như TypeScript (bao gồm cả Zod).
Nêu quan điểm rằng mọi API và hệ thống đều luôn thay đổi và thử nghiệm; thực tế có quá nhiều lớp phức tạp là một nhược điểm, nhưng trong những tình huống “chỉ cần công việc trong dự án chạy được” thì cuối cùng nó vẫn chỉ tạo thêm việc cho con người.
Nhìn tổng thể thì có thể dùng type safety end-to-end như
trpc, nhưng để làm vậy phải thống nhất cả frontend lẫn backend đều dùng TypeScript, và điều này khó áp dụng trong thực tế khi còn có các nền tảng ngoài web như mobile.Người này nói mình không phải chuyên gia, nhưng cho rằng JSON-Schema với cách tiếp cận dựa trên schema có thể là lựa chọn tốt vì có thể triển khai validator ở nhiều ngôn ngữ ngoài TypeScript, rồi hỏi về so sánh với Zod trên cơ sở các thư viện như ajv.js.org.
Giải thích rằng Zod không chỉ validate dữ liệu ở dạng JSON mà còn cả các đối tượng JS nói chung như ngày tháng, instance của class và những dữ liệu không thể biểu diễn bằng JSON. Nó cũng có thể dùng trong quá trình chuyển đổi dữ liệu JSON; có thể viết schema theo dạng chuỗi rồi validate và chuyển đổi, ví dụ từ ISO date string sang
Dateobject.Nói rằng Zod 4 hỗ trợ chuyển schema Zod sang JSON-Schema, trong khi trước đây phải cần thư viện ngoài. Điểm khác biệt lớn của Zod là các tính năng preprocess/refine, cho phép thêm callback trước khi validate để thực hiện các chuyển đổi linh hoạt như đổi
MM/DD/YYYYthànhDD/MM/YYYYrồi mới validate; điều này không làm được trong JSON-Schema.Nói rằng JSON-Schema cũng là một lựa chọn tốt, và trong trường hợp đó TypeBox phù hợp để sinh schema; có thể dùng
avjhoặc hệ thống validate riêng. Hệ thống riêng thì nhanh hơn nhưng chỉ đồng bộ, cònavjhỗ trợ cả validate bất đồng bộ nên có lợi nếu cần kiểm tra sâu hơn.Nếu muốn dùng trên nhiều ngôn ngữ thì JSON-Schema là lựa chọn phổ biến nhất; nếu bọc trong OpenAPI thì còn có thể tự động sinh tài liệu API.
Người này nói họ vừa bắt đầu đưa Zod vào một dự án mới, và cảm thấy thời điểm phát hành lần này đến quá hoàn hảo; nếu mọi thứ diễn ra đúng kế hoạch thì lẽ ra họ đã phải thay đổi rất nhiều để migrate sang v4, nên thời điểm này thật sự quá đẹp.
Phản ứng rằng họ ngạc nhiên vì có nhiều ý kiến tiêu cực hơn dự đoán. Khi thử các bản v4 đầu tiên, họ thích API mới nhưng lo ngại về lộ trình migrate, thậm chí từng nghĩ tới phương án phát hành dưới tên gói riêng; tuy nhiên họ đánh giá cách làm thực tế của tác giả đã giải quyết vấn đề cực kỳ xuất sắc. Nhờ vậy có thể áp dụng v4 ngay mà không cần phải chờ các dependency cập nhật.