- PR refactor trong kho lưu trữ Svelte năm 2023 đã chuyển sang mã dựa trên JSDoc, thu hút sự chú ý của những người hoài nghi TypeScript
- Phía Svelte giải thích rằng đây không phải là lập trường phản TypeScript, mà là một phần của sự phụ thuộc liên tục vào TypeScript
- Bài viết nhấn mạnh rằng không nên đặt JSDoc và TypeScript trong thế đối lập, mà bản thân JSDoc là một phần của TypeScript
- TypeScript đóng vai trò là động cơ IntelliSense, phụ trách cả việc diễn giải chú thích JSDoc lẫn tính năng tự động hoàn thành mã
- JSDoc cung cấp khả năng phân tích tĩnh tương đương mà không cần bước build, và trong các dự án JS hiện đại, trên thực tế đảm nhiệm vai trò giống như TypeScript
PR của Svelte và bối cảnh tranh cãi
- Tháng 5 năm 2023, PR refactor nội bộ trong kho lưu trữ Svelte đã lên trang nhất Hacker News
- PR này là thay đổi chuyển các khai báo kiểu từ file
.ts sang chú thích JSDoc trong file .js
- Một số người diễn giải đây là hành động phủ nhận lợi ích của TypeScript
- Nhà sáng lập Svelte Rich Harris đã trực tiếp giải thích trên HN rằng “đây không phải là chống TypeScript”
- Ông nói rằng cam kết của Svelte với TypeScript vẫn rất mạnh mẽ
- Sau sự kiện này, đã xuất hiện nhiều bài viết so sánh “TypeScript vs JSDoc”, và quan điểm đánh giá JSDoc là “TypeScript không có bước build” dần lan rộng
Nguồn gốc và bản chất của TypeScript
- Cuối những năm 2000 đến đầu những năm 2010, JavaScript được xem là ngôn ngữ thiếu tự động hoàn thành và an toàn kiểu
- Các nhà phát triển Microsoft đã đối phó bằng cách dùng ScriptSharp để chuyển mã C# sang JS
- Trong bối cảnh đó, TypeScript ra đời, và về bản chất ban đầu là một công cụ build để cải thiện việc phát triển JS
TypeScript là IntelliSense
- TypeScript không chỉ là một ngôn ngữ, mà còn đóng vai trò động cơ IntelliSense
- Ngay cả khi không dùng file
.ts, các tính năng như tự động hoàn thành mã, thông tin tham số, và điều hướng biểu tượng vẫn do dịch vụ ngôn ngữ TypeScript cung cấp
- Trong phần lớn editor, ngay cả khi viết mã JS, dịch vụ TypeScript vẫn chạy ở backend
TypeScript là JSDoc
- Dịch vụ ngôn ngữ TypeScript cũng được dùng để diễn giải chú thích JSDoc
- Trong CHANGELOG của TypeScript thường xuyên có các mục bổ sung tính năng liên quan đến JSDoc
- Các dự án dựa trên JSDoc cũng có thể được cấu hình bằng
tsconfig.json, và có thể dùng lệnh tsc để thực hiện kiểm tra kiểu
- Vì vậy, các nhà phát triển dùng JSDoc thực chất cũng đã đang dùng TypeScript
Kinh nghiệm với dự án dựa trên JSDoc
- Tác giả chia sẻ kinh nghiệm viết lại frontend của một dự án hiện có dựa trên chú thích kiểu JSDoc
- Ngoại trừ các tính năng runtime như enum, hầu hết biểu đạt của TypeScript đều có thể thực hiện bằng JSDoc
- Generic có cú pháp hơi phức tạp, nhưng điều đó lại khiến người viết tận dụng suy luận kiểu tích cực hơn
- Trong các dự án JSDoc, khi click vào hàm có thể đi tới mã nguồn thực tế, giúp cải thiện trải nghiệm phát triển
- Hệ sinh thái công cụ TypeScript cũng có thể được tái sử dụng trong các dự án JSDoc
- Ví dụ: các thư viện tạo kiểu từ schema OpenAPI hoặc GraphQL cũng có thể sinh kiểu dưới dạng chú thích JSDoc
Kết luận và các ví dụ bổ sung
- JSDoc không phải là lựa chọn thay thế cho TypeScript, mà chia sẻ cùng một hệ thống phân tích tĩnh
- Dù lược bỏ bước build, nó vẫn cung cấp độ an toàn kiểu tương đương
- Ngoài ra, bài viết cũng nhắc tới trường hợp dự án webpack đã migrate sang JSDoc
- Với tư cách là một chuyên gia TypeScript, tác giả khẳng định rõ lập trường: “JSDoc là TypeScript”
1 bình luận
Ý kiến trên Hacker News
Sau nhiều năm phát triển và bảo trì phần mềm web và robotics bằng Python/JavaScript, tôi đã rút ra vài điều
Kiểu dữ liệu vẫn luôn tồn tại kể cả khi không được khai báo, và nếu không khai báo thì cuối cùng nó chỉ tồn tại trong đầu bạn
Nhưng trí nhớ con người rất dễ phai và người khác thì khó tiếp cận được
Vì vậy, việc khai báo kiểu là một phương thức tài liệu hóa rất tốt
JSDoc và TypeScript là các định dạng tiêu chuẩn để biểu đạt kiểu, và cả hai đều có ưu và nhược điểm riêng
Điều quan trọng là định nghĩa kiểu một cách nhất quán và có thể dự đoán được
Bộ kiểm tra kiểu là cách máy tính nói rằng: “vậy hãy chứng minh đi”
Không phải mọi chương trình đều cần cùng một mức độ chứng minh, và việc chứng minh quá mức có thể là lãng phí
Vì thế tôi thích những ngôn ngữ có thể “chứng minh được” vừa đủ theo nhu cầu
Đặc biệt, khi đi làm tôi thấm thía rằng ‘người khác’ cũng bao gồm cả chính mình trong tương lai
Rust có thể nới lỏng ràng buộc bằng các cách như unsafe, Arc, clone, nhưng đổi lại nó buộc bạn phải chọn một cách rõ ràng xem ràng buộc nào chưa được chứng minh
Ngược lại, với những ngôn ngữ “không cần chứng minh”, rất khó biết nội bộ đã chọn cách tiếp cận nào
Cách tiếp cận của Rust lúc đầu có thể dùng lỏng như Python, nhưng về sau lại có lợi thế lớn hơn nhiều về tính dễ đọc và khả năng mở rộng
Tôi không định cổ vũ cho công cụ cụ thể nào, chỉ muốn nhấn mạnh rằng cả hai đều là cách biểu đạt của một hệ thống kiểu
Ngôn ngữ định kiểu tĩnh dễ xử lý hơn nhiều trong các dự án nhóm, và đến giờ nếu có thể tôi vẫn ưu tiên kiểu tĩnh
Nếu nhìn vào các định nghĩa kiểu TypeScript được thêm vào sau này cho các thư viện JS cũ thì mức độ phức tạp là cực lớn
Chỉ một kiểu sai cũng có thể làm hỏng toàn bộ quá trình biên dịch
Cuối cùng thì ngôn ngữ động phải được dùng theo kiểu ‘tự chịu trách nhiệm’
Tôi thích mọi thứ có thể làm bằng JavaScript mà không cần build step
HTML/CSS hiện đại, Web Components, và tổ hợp JSDoc hiện đang bị đánh giá thấp
Có thể không phù hợp với tất cả mọi người, nhưng tôi nghĩ đây là một ứng viên frontend stack đủ hiện đại
Nhờ các tính năng như HMR mà chi phí của build step cũng đã giảm đi rất nhiều
Lúc nào cũng đi qua Vite hay Webpack, nên tôi không thật sự cảm nhận được lợi ích của JS không cần build
Tôi ước gì có cách nào đó giúp tạo các component phức tạp dễ dàng hơn
Theo dõi request mạng, nhảy thẳng tới mã nguồn, đặt breakpoint... mọi thứ đều trực quan hơn nhiều khi debug
Khi quy mô lớn dần, môi trường như vậy rất hữu ích
Vào thời SPA còn thịnh hành, JSDoc là vị cứu tinh của việc quản lý kiểu
Sau đó Google Closure Compiler xuất hiện và cung cấp độ an toàn kiểu dựa trên JSDoc, còn TypeScript hỗ trợ (TS)JSDoc cùng với cú pháp riêng của nó
Cộng đồng cuối cùng đã chọn TypeScript và Closure Compiler biến mất
Vì vậy (TS)JSDoc trở thành di tích từ thời MS cạnh tranh với Google
Giờ đây TS cung cấp nhiều tính năng hơn hẳn như generic, Enum, utility type, kiểm thử kiểu với Vitest, type guard...
Tôi dùng cả TS lẫn JSDoc — TS cho code, JSDoc cho tài liệu (
@link,@see,@deprecated,@examplev.v.)Hầu hết tính năng của TS như generic, utility type, type guard, phân tích regex... đều có thể dùng trong JSDoc
Tôi đã thử triển khai mọi thứ bằng JSDoc trong dự án cá nhân, bao gồm cả generic
Nói rằng (TS)JSDoc là di tích quá khứ là thông tin sai lệch, không nên lan truyền khi chưa kiểm chứng
Có người nói có nhiều kiểu không thể biểu đạt bằng JSDoc, nhưng tôi nghĩ sẽ tốt hơn nếu có thể tiếp cận toàn bộ ngôn ngữ như Flow
TypeScript cũng có thể làm như vậy, nhưng tôi không hiểu vì sao lại không chọn hướng đó
Trước đây tôi cũng từng nghĩ vậy, nhưng sau khi refactor dự án sang JSDoc thì tôi đã đổi ý
Trong JSDoc cũng có thể định nghĩa generic slot bằng
@templateVí dụ:
Liên kết liên quan
Các package viết bằng JSDoc cho trải nghiệm phát triển tốt vì CMD/CTRL + click sẽ đưa tới mã nguồn thực tế
Ở một buổi meetup 5 năm trước, có diễn giả nói rằng “nếu ghét TypeScript thì JSDoc là giải pháp thay thế”
Tôi đã giải thích rằng rốt cuộc cả hai đều là TypeScript, nhưng sếp tôi không tin
JSDoc và TS đều biểu đạt kiểu một cách tường minh, nhưng cú pháp TS mạnh hơn nhiều
Dù vậy, với những ai muốn giữ nguyên môi trường JS mà vẫn hưởng lợi từ công cụ kiểu, JSDoc vẫn là một lựa chọn tốt
Ngược lại, JSDoc không phải là TypeScript
Kiểu được định nghĩa bằng
@typedefsẽ tự động được export và không có cách nào kiểm soát điều đóVấn đề liên quan
Vì vậy khi phát triển thư viện, IntelliSense bị lộ ra lộn xộn khiến tôi thấy rất bất tiện
Chỉ cần sao chép nguyên file “my-component.js” là có thể chạy ngay mà không cần build
Nhưng trong các dự án lớn, tôi vẫn thích cú pháp TS hơn
@importlà có thể giải quyết phần lớn vấn đềTôi đồng ý với nhận định “JSDoc không phải là giải pháp thay thế cho TypeScript”
JSDoc cũng cung cấp phân tích tĩnh nhưng không có build step
Xem tài liệu chính thức của Node
Nhưng TS dựa trên JSDoc vẫn hoạt động được trong trình duyệt
Cá nhân tôi thích độ dễ đọc của cú pháp TS hơn, và với các công cụ như
swcthì tốc độ loại bỏ kiểu cũng đủ nhanhLý do TypeScript vượt qua các lựa chọn khác để giành chiến thắng là vì nó vẫn là một bộ kiểm tra kiểu chứ không phải một ngôn ngữ mới
Dù định hướng ban đầu có hơi dao động, nó đã được điều chỉnh đúng lúc, và giờ trong phần lớn code thì ngay cả enum cũng hiếm khi được dùng
Trong VSCode, nếu bật tùy chọn “TypeScript: Prefer Go To Source Definition” thì có thể nhảy tới source thực tế
Ngoài ra, nếu thêm
declarationMap: truevàotsconfigthì sẽ hoạt động chính xác hơnTôi gần như luôn thích xem source khi cmd+click