1 điểm bởi GN⁺ 2025-12-16 | 1 bình luận | Chia sẻ qua WhatsApp
  • 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

 
GN⁺ 2025-12-16
Ý 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

    • Tôi hoàn toàn đồng ý với ý rằng “thông tin chỉ tồn tại trong đầu thì rất dễ biến mất”
      Đặ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 thường được biết đến như đại diện cho triết lý “prove it”, nhưng tôi nghĩ thực tế không hẳn vậy
      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 đồng ý rằng JSDoc và TypeScript có cùng mục đích
      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
    • Tôi đã học được bài học này từ 25 năm trước khi còn học đại học
      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
    • Tôi đồng ý với câu “kiểu luôn tồn tại”, nhưng các ngôn ngữ buộc phải khai báo kiểu như C# đòi hỏi nhiều công sức hơn Ruby rất nhiều
      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

    • Từ Node 24 trở đi, TypeScript cũng có thể chạy mà không cần build step
    • Tôi hiểu sức hấp dẫn của cách tiếp cận không có build step, nhưng trên thực tế việc quản lý phụ thuộc lại trở nên phức tạp hơn
      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
    • Suốt 10 năm qua tôi chưa từng tự viết mã JS được triển khai trực tiếp
      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
    • Web Components khá đau khổ để xây dựng
      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
    • Ưu điểm của tổ hợp HTML+CSS+JSDoc là tích hợp tự nhiên với công cụ dành cho nhà phát triển trong trình duyệt
      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, @example v.v.)

    • Trên thực tế, JSDoc hiện đại sử dụng dịch vụ ngôn ngữ TypeScript
      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
    • Khẳng định trên là không đúng sự thật
      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
    • Chính bài viết này là một lời phản bác trực tiếp cho khẳng định đó
  • 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 đó

    • Nếu có ví dụ cụ thể thì tôi rất muốn nghe
      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 @template
      Ví dụ:
      /** @type {ReturnType<typeof useState<Book[]>>} */
      const [books, setBooks] = useState();
      
    • Bây giờ gần như mọi tính năng của hệ thống kiểu đều đã được bổ sung vào cú pháp JSDoc
    • Hệ thống kiểu của TypeScript là Turing complete nên về thực tế có năng lực biểu đạt gần như vô hạn
      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ế

    • Điều này cũng có thể được tùy chỉnh bằng cài đặt editor
    • Thực ra trong TypeScript cũng hoạt động y như vậy
  • Ở 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

    • Tôi nghĩ khác biệt nằm ở mức độ nén cú pháp (syntax compression)
    • Câu “JSDoc rốt cuộc cũng là TypeScript” chỉ đúng một nửa
      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 @typedef sẽ 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

    • JSDoc khá hợp với Web Components
      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
    • Về mặt kỹ thuật thì nhận xét đó đúng, nhưng điều chỉnh @import là 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

    • Bên trong thì build step vẫn tồn tại
      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ư swc thì tốc độ loại bỏ kiểu cũng đủ nhanh
    • Tuy nhiên tính năng này chỉ giới hạn trong môi trường Node và không hoạt động trong trình duyệt
  • Lý 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: true vào tsconfig thì sẽ hoạt động chính xác hơn
    Tôi gần như luôn thích xem source khi cmd+click