---
id: ts-jsdoc-typescript
title: JSDoc + TypeScript — 빌드 없는 타입
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [typescript, jsdoc, vibe-coding]
tech_stack: { language: "TypeScript / JS", applicable_to: ["Backend", "Frontend"] }
applied_in: []
aliases: [JSDoc, allowJs, checkJs, type comments, no-build TS]
---

# JSDoc + TypeScript

> 빌드 없이 type 안전. **`.js` + JSDoc + `// @ts-check`** 가 가능. CDN 스크립트 / Deno / Bun 일부 / 작은 도구. 큰 코드는 그냥 `.ts`.

## 📖 핵심 개념
- VS Code / tsc 가 JSDoc 을 type 으로 해석.
- `// @ts-check` 한 파일만 검사.
- `tsconfig.json` `allowJs + checkJs` 모든 .js 검사.
- DTS 생성 = `tsc --emitDeclarationOnly`.

## 💻 코드 패턴

### 기본
```js
// @ts-check

/**
 * @param {string} name
 * @param {number} [age] - optional
 * @returns {{ name: string, age?: number }}
 */
function makeUser(name, age) {
  return { name, age };
}

makeUser('Alice');           // OK
makeUser('Alice', 'thirty'); // ❌ TS error
```

### Type alias (typedef)
```js
/**
 * @typedef {Object} User
 * @property {string} id
 * @property {string} email
 * @property {Date} createdAt
 */

/** @type {User} */
const u = { id: '1', email: 'a@b.com', createdAt: new Date() };
```

### Generic
```js
/**
 * @template T
 * @param {T[]} arr
 * @returns {T | undefined}
 */
function first(arr) { return arr[0]; }

const n = first([1, 2, 3]); // number | undefined
```

### Import type from .d.ts
```js
/** @typedef {import('./types').User} User */
/** @typedef {import('./types').Order} Order */

/** @type {User} */
const u = { ... };
```

### Cast
```js
const el = /** @type {HTMLInputElement} */ (document.getElementById('x'));
el.value;
```

### Conditional/union
```js
/**
 * @param {string | number} v
 */
function fmt(v) {
  if (typeof v === 'string') return v.toUpperCase();
  return v.toFixed(2);
}
```

### tsconfig (전체 .js 검사)
```jsonc
{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,
    "noEmit": true,
    "strict": true
  },
  "include": ["src/**/*"]
}
```

### DTS 만 생성 (배포)
```jsonc
{
  "compilerOptions": {
    "allowJs": true,
    "declaration": true,
    "emitDeclarationOnly": true,
    "outDir": "types"
  }
}
```

```bash
tsc
# types/*.d.ts 생성
```

```jsonc
// package.json
{ "main": "./src/index.js", "types": "./types/index.d.ts" }
```

### Deno / Bun (native TS)
- Deno: `.ts` 직접 실행, JSDoc 도 OK.
- Bun: `.ts` 직접 — JSDoc 안 쓰는 게 나음.

### 함수 overload
```js
/**
 * @overload
 * @param {string} v
 * @returns {string}
 *
 * @overload
 * @param {number} v
 * @returns {number}
 *
 * @param {string | number} v
 */
function double(v) {
  return /** @type {any} */ (typeof v === 'string' ? v + v : v * 2);
}
```

## 🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| 작은 도구 / script | JSDoc |
| Library 배포 (no build) | JSDoc + emitDeclarationOnly |
| Deno / Bun | TS 직접 또는 JSDoc |
| Browser direct (CDN) | JSDoc |
| 큰 앱 / 팀 | TS 직접 (.ts) |
| Legacy JS 점진 마이그레이션 | // @ts-check 부분 도입 |

## ❌ 안티패턴
- **JSDoc + .ts**: 둘 다? .ts 면 JSDoc 불필요.
- **@ts-check 없이 JSDoc**: 검사 안 됨.
- **Cast 남발 (`/** @type ... */`)**: type 우회 — 의도 검토.
- **import type 누락**: any.
- **JSDoc 으로 generic 복잡**: TS .ts 가 가독성 좋음.
- **VSCode 만 — CI 검사 없음**: 안전망 부재. tsc CI.

## 🤖 LLM 활용 힌트
- 빌드 없는 TS = JSDoc + checkJs.
- DTS 만 export = emitDeclarationOnly.
- 큰 코드는 .ts.

## 🔗 관련 문서
- [[TS_tsconfig_Strategy]]
- [[TS_Build_Bundler_Patterns]]
- [[JS_Module_System_ESM_CJS]]
