1P by GN⁺ 22시간전 | ★ favorite | 댓글 1개
  • 2023년 Svelte 저장소의 리팩터링 PR이 JSDoc 기반 코드로 전환되며 TypeScript 회의론자들의 주목을 받음
  • Svelte 측은 이를 반(反) TypeScript 입장이 아니라, TypeScript에 대한 지속적 의존의 일환으로 설명
  • 글은 JSDoc과 TypeScript를 대립 구도로 보지 않고, JSDoc 자체가 TypeScript의 일부임을 강조
  • TypeScript는 IntelliSense 엔진으로서, JSDoc 주석 해석과 코드 자동완성 기능을 모두 담당
  • JSDoc은 빌드 단계 없이 동일한 정적 분석 능력을 제공하며, 현대 JS 프로젝트에서 실질적으로 TypeScript와 동일한 역할 수행

Svelte PR과 논란의 배경

  • 2023년 5월, Svelte 저장소의 내부 리팩터링 PR이 Hacker News 첫 페이지에 오름
    • 이 PR은 .ts 파일의 타입 선언을 .js 파일의 JSDoc 주석으로 옮기는 변경이었음
    • 일부에서는 이를 TypeScript의 이점을 거부하는 행위로 해석
  • Svelte 창시자 Rich Harris는 HN에서 직접 “이는 TypeScript 반대가 아니다”라고 설명
    • Svelte의 TypeScript에 대한 헌신은 여전히 강력하다고 언급
  • 이 사건 이후 “TypeScript vs JSDoc” 비교 글이 다수 등장하며, JSDoc을 “빌드 단계 없는 TypeScript”로 평가하는 흐름이 확산

TypeScript의 기원과 본질

  • 2000년대 후반~2010년대 초, JavaScript는 자동완성·타입 안전성이 부족한 언어로 인식됨
    • Microsoft 개발자들은 ScriptSharp을 사용해 C# 코드를 JS로 변환하는 방식으로 대응
  • 이러한 배경에서 TypeScript가 탄생, 본질적으로는 JS 개발을 개선하기 위한 빌드 도구로 출발

TypeScript는 IntelliSense

  • TypeScript는 단순한 언어가 아니라 IntelliSense 엔진 역할 수행
    • .ts 파일을 사용하지 않아도, 코드 자동완성·매개변수 정보·심볼 탐색 등 기능은 TypeScript 언어 서비스가 제공
    • 대부분의 에디터에서 JS 코드 작성 시에도 TypeScript 서비스가 백엔드로 동작

TypeScript는 JSDoc

  • TypeScript 언어 서비스는 JSDoc 주석 해석에도 사용됨
    • TypeScript의 CHANGELOG에는 JSDoc 관련 기능 추가 내역이 자주 포함
    • JSDoc 기반 프로젝트도 tsconfig.json으로 설정 가능하며, tsc 명령으로 타입 검사 수행 가능
  • 따라서 JSDoc을 사용하는 개발자도 이미 TypeScript를 사용 중인 셈

JSDoc 기반 프로젝트 경험

  • 작성자는 기존 프로젝트 프런트엔드를 JSDoc 타입 주석 기반으로 재작성한 경험을 공유
    • 열거형(enum) 같은 런타임 기능을 제외하면, 대부분의 TypeScript 표현이 JSDoc으로 가능
    • 제네릭은 문법이 다소 복잡하지만, 타입 추론을 더 적극적으로 활용하게 함
  • JSDoc 프로젝트에서는 함수 클릭 시 실제 코드로 이동할 수 있어 개발 경험이 향상
  • TypeScript 도구 생태계는 JSDoc 프로젝트에서도 재사용 가능
    • 예: OpenAPI나 GraphQL 스키마에서 타입을 생성하는 라이브러리들이 JSDoc 주석 형태로 타입 생성 가능

결론 및 추가 사례

  • JSDoc은 TypeScript의 대안이 아니라 동일한 정적 분석 체계를 공유
    • 빌드 단계를 생략하면서도 동등한 타입 안정성을 제공
  • 추가로, webpack 프로젝트도 JSDoc으로 마이그레이션한 사례가 언급됨
  • TypeScript 전문가로서, 작성자는 “JSDoc은 TypeScript다”라는 입장을 명확히 제시
Hacker News 의견들
  • 여러 해 동안 Python/JavaScript로 웹과 로보틱스 소프트웨어를 개발하고 유지보수하며 배운 점을 정리했음
    타입은 명시하지 않아도 존재하며, 명시하지 않으면 결국 머릿속에만 존재하게 됨
    하지만 머리는 휘발성이 강하고 다른 사람이 접근하기 어려움
    그래서 타이핑은 훌륭한 문서화 수단
    JSDoc과 TypeScript는 타입을 표현하는 표준 형식이며, 둘 다 장단점이 있음
    중요한 건 일관성과 예측 가능성 있게 타입을 정의하는 것임
    타입 체커는 “그럼 증명해봐”라고 말하는 컴퓨터의 방식임
    모든 프로그램이 같은 수준의 증명을 필요로 하진 않으며, 과도한 증명은 낭비가 될 수 있음
    그래서 나는 필요한 만큼만 “증명할 수 있는” 언어를 선호함

    • “머릿속에만 있는 정보는 휘발성이 강하다”는 말에 완전히 공감함
      특히 ‘다른 사람’에는 미래의 나 자신도 포함됨이라는 걸 일하면서 절실히 배웠음
    • Rust는 “prove it” 철학의 대표로 알려져 있지만, 실제로는 그렇지 않다고 생각함
      Rust는 unsafe, Arc, clone 같은 방식으로 제약을 완화할 수 있지만, 그 대신 어떤 제약이 증명되지 않았는지를 명확히 선택하게 함
      반면 “증명하지 않아도 되는” 언어는 내부적으로 어떤 접근을 택했는지 알기 어려움
      Rust의 접근은 초반에는 Python처럼 느슨하게 쓸 수 있지만, 이후 가독성과 확장성에서 훨씬 유리함
    • JSDoc과 TypeScript가 동일한 목적을 가진다는 점에 동의함
      특정 도구를 옹호하려는 의도는 아니었고, 단지 둘 다 타입 시스템의 표현 방식이라는 점을 강조하고 싶었음
    • 25년 전 대학 시절에 이미 이 교훈을 배웠음
      정적 타이핑 언어가 팀 프로젝트에서 훨씬 다루기 쉬웠고, 지금도 가능하면 정적 타입을 선호함
    • “타입은 항상 존재한다”는 말에는 동의하지만, C#처럼 타입을 명시해야 하는 언어는 Ruby보다 훨씬 많은 작업이 필요함
      기존 JS 라이브러리에 나중에 추가된 TypeScript 타입 정의를 보면 복잡성이 엄청남
      잘못된 타입 하나로도 전체 컴파일이 깨질 수 있음
      결국 동적 언어는 ‘스스로 책임지는’ 방식으로 써야 함
  • 나는 빌드 스텝 없이 JavaScript로 만들 수 있는 모든 것을 좋아함
    현대 HTML/CSS와 Web Components, 그리고 JSDoc 조합은 과소평가되어 있음
    모두에게 맞진 않지만, 충분히 현대적인 프런트엔드 스택 후보라고 생각함

    • 이제 Node 24부터는 TypeScript도 빌드 스텝 없이 실행 가능함
    • 빌드 스텝이 없는 접근의 매력은 이해하지만, 실제로는 의존성 관리가 복잡해짐
      HMR 같은 기능 덕분에 빌드 스텝의 비용도 많이 줄어듦
    • 지난 10년간 실제로 배포된 JS 코드를 직접 쓴 적이 없음
      항상 Vite나 Webpack을 거치기 때문에 빌드 없는 JS의 장점은 체감되지 않음
    • Web Components는 만들기 꽤 고통스러움
      복잡한 컴포넌트를 쉽게 만드는 방법이 있었으면 좋겠음
    • HTML+CSS+JSDoc 조합의 장점은 브라우저 개발자 도구와의 자연스러운 통합
      네트워크 요청 추적, 소스 코드로 바로 이동, 브레이크포인트 설정 등 디버깅이 훨씬 직관적임
      규모가 커질수록 이런 환경이 큰 도움이 됨
  • SPA가 유행하던 시절, JSDoc은 타입 관리의 구세주였음
    이후 Google Closure Compiler가 등장해 JSDoc 기반 타입 안전성을 제공했고, TypeScript가 자체 문법과 함께 (TS)JSDoc을 지원함
    커뮤니티는 결국 TypeScript를 선택했고 Closure Compiler는 사라짐
    그래서 (TS)JSDoc은 MS가 Google과 경쟁하던 시절의 유물로 남음
    지금은 TS가 제네릭, Enum, 유틸리티 타입, Vitest 타입 테스트, 타입가드 등 훨씬 많은 기능을 제공함
    나는 TS와 JSDoc을 함께 씀 — TS는 코드용, JSDoc은 문서용 (@link, @see, @deprecated, @example 등)

    • 실제로 현대 JSDoc은 TypeScript 언어 서비스를 사용함
      제네릭, 유틸리티 타입, 타입가드, 정규식 파싱 등 대부분의 TS 기능을 JSDoc에서도 활용 가능함
      개인 프로젝트에서 제네릭을 포함해 전부 JSDoc으로 구현해봤음
    • 위 주장은 사실이 아님
      (TS)JSDoc이 과거의 유물이라는 건 잘못된 정보이므로 확인 없이 퍼뜨리지 말아야 함
    • 이 글 자체가 바로 그 주장에 대한 직접적인 반박
  • JSDoc으로 표현할 수 없는 타입이 많다고 하지만, Flow처럼 전체 언어 접근이 가능했다면 좋았을 것 같음
    TypeScript도 그렇게 할 수 있었는데 왜 안 했는지 모르겠음

    • 구체적인 예시가 있다면 듣고 싶음
      나도 예전엔 그렇게 생각했지만, 프로젝트를 JSDoc으로 리팩터링하면서 생각이 바뀜
      JSDoc에서도 @template으로 제네릭 슬롯을 정의할 수 있음
      예:
      /** @type {ReturnType<typeof useState<Book[]>>} */
      const [books, setBooks] = useState();
      
    • 이제는 거의 모든 타입 시스템 기능이 JSDoc 문법에도 추가되어 있음
    • TypeScript의 타입 시스템은 튜링 완전(Turing complete) 하므로 사실상 무한한 표현력을 가짐
      관련 링크
  • JSDoc으로 작성된 패키지는 CMD/CTRL 클릭 시 실제 코드로 이동할 수 있어서 개발자 경험이 좋음

    • 이건 에디터 설정으로도 커스터마이징 가능함
    • 사실 TypeScript에서도 동일하게 작동함
  • 5년 전 밋업에서 어떤 발표자가 “TypeScript가 싫다면 JSDoc이 대안”이라고 말했음
    나는 그게 결국 둘 다 TypeScript라고 설명했지만, 내 상사는 믿지 않았음

    • 차이는 문법의 압축도(syntax compression) 정도라고 생각함
    • “JSDoc도 결국 TypeScript다”라는 말은 절반만 맞음
      JSDoc과 TS는 모두 타입을 명시적으로 표현하지만, TS 문법이 훨씬 강력함
      그래도 JS 환경을 유지하면서 타입 도구의 혜택을 얻고 싶은 사람에게는 JSDoc이 좋은 선택임
  • 반론으로, JSDoc은 TypeScript가 아님
    @typedef로 정의한 타입은 자동으로 export되며, 이를 제어할 방법이 없음
    관련 이슈
    이 때문에 라이브러리 개발 시 IntelliSense가 어지럽게 노출되어 불편했음

    • Web Components에는 JSDoc이 꽤 잘 맞음
      “my-component.js” 파일을 그대로 복사해도 빌드 없이 동작함
      하지만 대형 프로젝트에서는 TS 문법을 선호함
    • 기술적으로는 맞는 지적이지만, @import를 조절하면 대부분 해결 가능함
  • “JSDoc은 TypeScript의 대안이 아니다”라는 주장에 동의함
    JSDoc도 정적 분석을 제공하지만 빌드 스텝이 없음
    Node 공식 문서 참고

    • 내부적으로는 여전히 빌드 스텝이 존재함
      하지만 JSDoc 기반 TS는 브라우저에서도 작동함
      나는 개인적으로 TS 문법의 가독성을 선호하며, swc 같은 도구로 타입 제거 속도도 충분히 빠름
    • 다만 이 기능은 Node 환경에 한정되어 있고 브라우저에서는 동작하지 않음
  • TypeScript가 다른 대안들을 제치고 승리한 이유는, 새로운 언어가 아니라 타입 체커로 남았기 때문
    초기에 방향이 다소 흔들렸지만, 적절히 수정했고 지금은 대부분의 코드에서 enums조차 잘 쓰지 않음

  • VSCode에서는 “TypeScript: Prefer Go To Source Definition” 설정을 켜면 실제 소스로 이동 가능함
    또한 tsconfigdeclarationMap: true를 추가하면 더 정확하게 작동함
    나는 거의 항상 cmd+click 시 소스 보기를 선호함