Ver3.0 ๐ ํ์ ์คํฌ๋ฆฝํธ ๋ฌธ์ํ์ TSDoc์ผ๋ก API ๋ฌธ์ ์๋ ์์ฑํ๊ธฐ

๐ ํ์ ์คํฌ๋ฆฝํธ ๋ฌธ์ํ์ TSDoc์ผ๋ก API ๋ฌธ์ ์๋ ์์ฑํ๊ธฐ
๐ฏ ์ ๋ฌธ์ํ๊ฐ ์ค์ํ ๊น?
์๋ ! ์ค๋์ ํ์ ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์๋ผ๋ฉด ๊ผญ ์์์ผ ํ ๋ฌธ์ํ์ TSDoc์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ๊ฒ. ํน์ 6๊ฐ์ ์ ์ ์์ฑํ ์ฝ๋๋ฅผ ๋ค์ ๋ดค๋๋ฐ "์ด๊ฒ ๋ญ์ง?" ํ๋ฉด์ ๋นํฉํ ๊ฒฝํ ์์ด? ๐ ์๋๋ฉด ํ์์ด ์์ฑํ ํจ์๋ฅผ ์ฌ์ฉํ๋ ค๋๋ฐ ํ๋ผ๋ฏธํฐ๊ฐ ๋ญ ์๋ฏธํ๋์ง ๋ชฐ๋ผ์ ์ง์ ๋ฌผ์ด๋ณธ ์ ์? ์ด๋ฐ ์ํฉ๋ค์ด ๋ฐ๋ก ๋ฌธ์ํ๊ฐ ํ์ํ ์ด์ ์ผ. ์ข์ ๋ฌธ์ํ๋ ์ฝ๋์ ์ดํด๋๋ฅผ ๋์ด๊ณ , ํ์ ์ ์ํํ๊ฒ ๋ง๋ค๋ฉฐ, ์ ์ง๋ณด์ ๋น์ฉ์ ํฌ๊ฒ ์ค์ฌ์ค. ํนํ ํ์ ์คํฌ๋ฆฝํธ์์๋ TSDoc์ด๋ผ๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ํตํด ์ฝ๋ ์ฃผ์์ ์์ฑํ๋ฉด ์๋์ผ๋ก ๋ฉ์ง API ๋ฌธ์๋ฅผ ์์ฑํ ์ ์์ด! ๐๐ค ํ์ ํจ์จ์ฑ: ํ์๋ค์ด ์ฝ๋๋ฅผ ๋น ๋ฅด๊ฒ ์ดํดํ๊ณ ์ฌ์ฉ
โฐ ์๊ฐ ์ ์ฝ: ๋ฐ๋ณต์ ์ธ ์ง๋ฌธ๊ณผ ์ค๋ช ์๊ฐ ๊ฐ์
๐ง ์ ์ง๋ณด์ ์ฉ์ด: ๋ฏธ๋์ ๋์ ํ์์ ์ํ ๋ฐฐ๋ ค
๐ TSDoc์ด๋ ๋ฌด์์ธ๊ฐ?
TSDoc์ ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ํ ํ์คํ๋ ๋ฌธ์ ์ฃผ์ ํ์์ด์ผ. ์๋ฐ์คํฌ๋ฆฝํธ์ JSDoc์์ ์๊ฐ์ ๋ฐ์์ง๋ง, ํ์ ์คํฌ๋ฆฝํธ์ ํน์ฑ์ ๋ง๊ฒ ์ต์ ํ๋์ด ์์ด. ๋ง์ดํฌ๋ก์ํํธ๊ฐ ์ฃผ๋ํ์ฌ ๊ฐ๋ฐํ๊ณ , ํ์ฌ๋ ์คํ์์ค ์ปค๋ฎค๋ํฐ์ ํจ๊ป ๋ฐ์ ํ๊ณ ์์ง. ๐จ TSDoc์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ ์ผ๊ด์ฑ์ด์ผ. ์ฌ๋ฌ ๊ฐ๋ฐ์๊ฐ ๊ฐ์ ๋ค๋ฅธ ์คํ์ผ๋ก ์ฃผ์์ ์์ฑํ๋ฉด ํผ๋์ค๋ฝ์์? TSDoc์ ๋ช ํํ ๊ท์น์ ์ ๊ณตํด์ ๋๊ฐ ์์ฑํ๋ ๊ฐ์ ํ์์ ์ ์งํ ์ ์๊ฒ ํด์ค.๐ TSDoc์ ํต์ฌ ํน์ง
2. ๋งํฌ๋ค์ด ์ง์
์ฃผ์ ์์์ ๋งํฌ๋ค์ด ๋ฌธ๋ฒ์ ์ฌ์ฉํ ์ ์์ด. ๋งํฌ, ์ฝ๋ ๋ธ๋ก, ๋ฆฌ์คํธ ๋ฑ์ ์์ ๋กญ๊ฒ ํ์ฉํด์ ๋ ํ๋ถํ ๋ฌธ์๋ฅผ ๋ง๋ค ์ ์์ง. โ๏ธ
3. ํ์ ์คํฌ๋ฆฝํธ ํตํฉ
ํ์ ์คํฌ๋ฆฝํธ์ ํ์ ์์คํ ๊ณผ ์๋ฒฝํ๊ฒ ํตํฉ๋ผ. IDE์์ ์๋์์ฑ์ด๋ ํธ๋ฒ ํดํ์ผ๋ก ๋ฌธ์๋ฅผ ๋ฐ๋ก ํ์ธํ ์ ์์ด.
๐ป ๊ธฐ๋ณธ TSDoc ๋ฌธ๋ฒ
TSDoc ์ฃผ์์ /**๋ก ์์ํด์ */๋ก ๋๋. ์ผ๋ฐ ์ฃผ์๊ณผ ๊ตฌ๋ถํ๊ธฐ ์ํด ๋ณํ๊ฐ ๋ ๊ฐ์ธ ๊ฑฐ์ผ. ๊ธฐ๋ณธ์ ์ธ ์์ ๋ฅผ ๋ณผ๊น?/**
* ๋ ์ซ์๋ฅผ ๋ํ๋ ํจ์์
๋๋ค.
*
* @param a - ์ฒซ ๋ฒ์งธ ์ซ์
* @param b - ๋ ๋ฒ์งธ ์ซ์
* @returns ๋ ์ซ์์ ํฉ
*
* @example
* ```typescript
* const result = add(5, 3);
* console.log(result); // 8
* ```
*/
function add(a: number, b: number): number {
return a + b;
}
๋ณด๋ค์ํผ ๊ตฌ์กฐ๊ฐ ๋ช
ํํ์ง? ํจ์์ ๋ชฉ์ , ํ๋ผ๋ฏธํฐ ์ค๋ช
, ๋ฐํ๊ฐ, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ ์์ ๊น์ง ํ๋์ ๋ค์ด์. ๐
๐ท๏ธ ์ฃผ์ TSDoc ํ๊ทธ ์๋ฒฝ ๊ฐ์ด๋
TSDoc์๋ ๋ค์ํ ํ๊ทธ๊ฐ ์์ด. ๊ฐ ํ๊ทธ๋ ํน์ ๋ชฉ์ ์ ๊ฐ์ง๊ณ ์๊ณ , ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๋ฉด ๋ฌธ์์ ํ์ง์ด ํฌ๊ฒ ํฅ์๋ผ. ์์ฃผ ์ฌ์ฉํ๋ ํ๊ทธ๋ค์ ํ๋์ฉ ์ดํด๋ณด์! ๐ฏ๐ ๊ธฐ๋ณธ ํ๊ทธ
| ํ๊ทธ | ์ฉ๋ | ์์ |
|---|---|---|
| @param | ํจ์ ํ๋ผ๋ฏธํฐ ์ค๋ช | @param userId - ์ฌ์ฉ์ ๊ณ ์ ID |
| @returns | ๋ฐํ๊ฐ ์ค๋ช | @returns ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ฒด |
| @throws | ๋ฐ์ ๊ฐ๋ฅํ ์์ธ | @throws {Error} ์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ ๋ |
| @example | ์ฌ์ฉ ์์ | ์ฝ๋ ์ํ ์ ๊ณต |
| @remarks | ์ถ๊ฐ ์ค๋ช | ์ฃผ์์ฌํญ์ด๋ ์์ธ ์ ๋ณด |
๐ง @param ํ๊ทธ ์์ธ ํ์ฉ
@param ํ๊ทธ๋ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ํ๊ทธ ์ค ํ๋์ผ. ํจ์์ ๊ฐ ํ๋ผ๋ฏธํฐ๊ฐ ๋ฌด์์ ์๋ฏธํ๋์ง ๋ช ํํ๊ฒ ์ค๋ช ํด์ค์ผ ํด./**
* ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.
*
* @param userId - ์
๋ฐ์ดํธํ ์ฌ์ฉ์์ ๊ณ ์ ์๋ณ์
* @param data - ์
๋ฐ์ดํธํ ๋ฐ์ดํฐ ๊ฐ์ฒด
* @param data.name - ์ฌ์ฉ์ ์ด๋ฆ (์ ํ์ฌํญ)
* @param data.email - ์ด๋ฉ์ผ ์ฃผ์ (์ ํ์ฌํญ)
* @param options - ์ถ๊ฐ ์ต์
* @param options.validateEmail - ์ด๋ฉ์ผ ์ ํจ์ฑ ๊ฒ์ฌ ์ฌ๋ถ (๊ธฐ๋ณธ๊ฐ: true)
*/
function updateUser(
userId: string,
data: { name?: string; email?: string },
options?: { validateEmail?: boolean }
): void {
// ๊ตฌํ ์ฝ๋
}
๊ฐ์ฒด ํ๋ผ๋ฏธํฐ์ ์์ฑ๊น์ง ๋ฌธ์ํํ ์ ์๋ค๋ ๊ฒ ํฌ์ธํธ์ผ! ๐ช ์ ํ๊ธฐ๋ฒ์ ์ฌ์ฉํด์ ์ค์ฒฉ๋ ์์ฑ๋ ์ค๋ช
ํ ์ ์์ด.
๐ค @returns ํ๊ทธ ํ์ฉ
๋ฐํ๊ฐ์ ๋ช ํํ๊ฒ ์ค๋ช ํ๋ ๊ฒ๋ ์ค์ํด. ๋จ์ํ ํ์ ๋ง ์๋ ค์ฃผ๋ ๊ฒ ์๋๋ผ, ์ด๋ค ์ํฉ์์ ์ด๋ค ๊ฐ์ ๋ฐํํ๋์ง ์ค๋ช ํด์ค์ผ ํด./**
* ์ฌ์ฉ์๋ฅผ ๊ฒ์ํฉ๋๋ค.
*
* @param query - ๊ฒ์ ์ฟผ๋ฆฌ
* @returns ๊ฒ์๋ ์ฌ์ฉ์ ๋ฐฐ์ด. ๊ฒฐ๊ณผ๊ฐ ์์ผ๋ฉด ๋น ๋ฐฐ์ด์ ๋ฐํํฉ๋๋ค.
* ๊ฐ ์ฌ์ฉ์ ๊ฐ์ฒด๋ id, name, email ์์ฑ์ ํฌํจํฉ๋๋ค.
*/
async function searchUsers(query: string): Promise<User[]> {
// ๊ตฌํ ์ฝ๋
}
โ ๏ธ @throws ํ๊ทธ๋ก ์์ธ ๋ฌธ์ํ
ํจ์๊ฐ ์ด๋ค ์ํฉ์์ ์๋ฌ๋ฅผ ๋์ง๋์ง ์๋ ค์ฃผ๋ ๊ฑด ์ ๋ง ์ค์ํด. ์ด๊ฑธ ๋ชจ๋ฅด๋ฉด ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ ๋๋ก ํ ์ ์๊ฑฐ๋ ./**
* ํ์ผ์ ์ฝ์ด์ JSON์ผ๋ก ํ์ฑํฉ๋๋ค.
*
* @param filePath - ์ฝ์ ํ์ผ ๊ฒฝ๋ก
* @returns ํ์ฑ๋ JSON ๊ฐ์ฒด
* @throws {FileNotFoundError} ํ์ผ์ด ์กด์ฌํ์ง ์์ ๋
* @throws {ParseError} JSON ํ์ฑ์ ์คํจํ์ ๋
* @throws {PermissionError} ํ์ผ ์ฝ๊ธฐ ๊ถํ์ด ์์ ๋
*/
function readJsonFile(filePath: string): object {
// ๊ตฌํ ์ฝ๋
}
๐ @example ํ๊ทธ๋ก ์ฌ์ฉ๋ฒ ๋ณด์ฌ์ฃผ๊ธฐ
์์ ๋ ์ฒ ๋ง๋ ๋ง๋ณด๋ค ๋ซ์ง! ๐ ์ค์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๋ณด์ฌ์ฃผ๋ฉด ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ด ํจ์ฌ ์ฝ๊ฒ ์ดํดํ ์ ์์ด./**
* ๋ฐฐ์ด์์ ์ค๋ณต์ ์ ๊ฑฐํฉ๋๋ค.
*
* @param array - ์ค๋ณต์ ์ ๊ฑฐํ ๋ฐฐ์ด
* @returns ์ค๋ณต์ด ์ ๊ฑฐ๋ ์ ๋ฐฐ์ด
*
* @example
* ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ:
* ```typescript
* const numbers = [1, 2, 2, 3, 3, 3, 4];
* const unique = removeDuplicates(numbers);
* console.log(unique); // [1, 2, 3, 4]
* ```
*
* @example
* ๊ฐ์ฒด ๋ฐฐ์ด์์ ์ฌ์ฉ:
* ```typescript
* const users = [
* { id: 1, name: 'Alice' },
* { id: 1, name: 'Alice' },
* { id: 2, name: 'Bob' }
* ];
* const uniqueUsers = removeDuplicates(users);
* // [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
* ```
*/
function removeDuplicates<T>(array: T[]): T[] {
return Array.from(new Set(array));
}
์ฌ๋ฌ ๊ฐ์ @example ํ๊ทธ๋ฅผ ์ฌ์ฉํด์ ๋ค์ํ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๋ณด์ฌ์ค ์ ์์ด. ๊ฐ ์์ ์๋ ์ค๋ช
์ ์ถ๊ฐํ๋ฉด ๋ ์ข์!
๐จ ๊ณ ๊ธ TSDoc ๊ธฐ๋ฒ
๊ธฐ๋ณธ ํ๊ทธ๋ค์ ์ตํ๋ค๋ฉด, ์ด์ ์ข ๋ ๊ณ ๊ธ ๊ธฐ๋ฒ๋ค์ ์์๋ณผ ์ฐจ๋ก์ผ. ์ด๋ฐ ๊ธฐ๋ฒ๋ค์ ํ์ฉํ๋ฉด ์ ๋ง ์ ๋ฌธ์ ์ธ ๋ฌธ์๋ฅผ ๋ง๋ค ์ ์์ด! ๐๐ @see ํ๊ทธ๋ก ๊ด๋ จ ํญ๋ชฉ ์ฐ๊ฒฐ
์ฝ๋๋ฒ ์ด์ค์์ ๊ด๋ จ๋ ํจ์๋ ํด๋์ค๋ฅผ ์ฐธ์กฐํ ๋ @see ํ๊ทธ๋ฅผ ์ฌ์ฉํด. ์ด๋ ๊ฒ ํ๋ฉด ๋ฌธ์๋ฅผ ์ฝ๋ ์ฌ๋์ด ๊ด๋ จ ์ ๋ณด๋ฅผ ์ฝ๊ฒ ์ฐพ์ ์ ์์ด./**
* ์ฌ์ฉ์๋ฅผ ์์ฑํฉ๋๋ค.
*
* @param userData - ์์ฑํ ์ฌ์ฉ์ ๋ฐ์ดํฐ
* @returns ์์ฑ๋ ์ฌ์ฉ์ ๊ฐ์ฒด
*
* @see {@link updateUser} - ์ฌ์ฉ์ ์ ๋ณด ์
๋ฐ์ดํธ
* @see {@link deleteUser} - ์ฌ์ฉ์ ์ญ์
* @see https://docs.example.com/user-management - ์ฌ์ฉ์ ๊ด๋ฆฌ ๊ฐ์ด๋
*/
function createUser(userData: UserData): User {
// ๊ตฌํ ์ฝ๋
}
๐ฆ @typeParam์ผ๋ก ์ ๋ค๋ฆญ ํ์ ์ค๋ช
์ ๋ค๋ฆญ์ ์ฌ์ฉํ๋ ํจ์๋ ํด๋์ค์์๋ @typeParam ํ๊ทธ๋ก ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ค๋ช ํ ์ ์์ด./**
* ๋ฐฐ์ด์ ๊ฐ ์์๋ฅผ ๋ณํํฉ๋๋ค.
*
* @typeParam T - ์
๋ ฅ ๋ฐฐ์ด์ ์์ ํ์
* @typeParam U - ์ถ๋ ฅ ๋ฐฐ์ด์ ์์ ํ์
* @param array - ๋ณํํ ๋ฐฐ์ด
* @param mapper - ๊ฐ ์์๋ฅผ ๋ณํํ๋ ํจ์
* @returns ๋ณํ๋ ์ ๋ฐฐ์ด
*
* @example
* ```typescript
* const numbers = [1, 2, 3];
* const strings = map(numbers, n => n.toString());
* // ['1', '2', '3']
* ```
*/
function map<T, U>(array: T[], mapper: (item: T) => U): U[] {
return array.map(mapper);
}
๐ท๏ธ @deprecated๋ก ์ฌ์ฉ ์ค๋จ ํ์
API๊ฐ ๋ณ๊ฒฝ๋๊ฑฐ๋ ๋ ๋์ ๋์์ด ์๊ฒผ์ ๋, ๊ธฐ์กด ํจ์๋ฅผ ๋ฐ๋ก ์ญ์ ํ๋ฉด ์ ๋์ง. ๋์ @deprecated ํ๊ทธ๋ก ํ์ํ๊ณ ๋์์ ์๋ดํด์ค์ผ ํด. โ ๏ธ/**
* ์ฌ์ฉ์ ๋ชฉ๋ก์ ๊ฐ์ ธ์ต๋๋ค.
*
* @deprecated ์ด ํจ์๋ v2.0์์ ์ ๊ฑฐ๋ ์์ ์
๋๋ค.
* ๋์ {@link getUsersPaginated}๋ฅผ ์ฌ์ฉํ์ธ์.
*
* @returns ๋ชจ๋ ์ฌ์ฉ์ ๋ฐฐ์ด
*/
function getUsers(): User[] {
// ๊ตฌํ ์ฝ๋
}
/**
* ํ์ด์ง๋ค์ด์
์ ์ง์ํ๋ ์ฌ์ฉ์ ๋ชฉ๋ก์ ๊ฐ์ ธ์ต๋๋ค.
*
* @param page - ํ์ด์ง ๋ฒํธ (1๋ถํฐ ์์)
* @param limit - ํ์ด์ง๋น ํญ๋ชฉ ์
* @returns ํ์ด์ง๋ค์ด์
๋ ์ฌ์ฉ์ ๋ชฉ๋ก
*/
function getUsersPaginated(page: number, limit: number): PaginatedUsers {
// ๊ตฌํ ์ฝ๋
}
๐ญ @internal๋ก ๋ด๋ถ API ํ์
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ๋ฐํ ๋, ์ธ๋ถ์ ๊ณต๊ฐํ์ง ์์ ๋ด๋ถ ํจ์๋ ํด๋์ค๊ฐ ์์ ์ ์์ด. @internal ํ๊ทธ๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฐ ํญ๋ชฉ๋ค์ ๊ณต๊ฐ ๋ฌธ์์์ ์ ์ธํ ์ ์์ด./**
* @internal
* ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉ๋๋ ํฌํผ ํจ์์
๋๋ค.
* ์ธ๋ถ์์ ์ง์ ํธ์ถํ์ง ๋ง์ธ์.
*/
function _internalHelper(): void {
// ๊ตฌํ ์ฝ๋
}
โ @param + @throws: ํ๋ผ๋ฏธํฐ ๊ฒ์ฆ ์คํจ ์ ์์ธ
โ @example + @see: ์์ ์ ๊ด๋ จ ๋ฌธ์ ๋งํฌ
โ @deprecated + @see: ๋์ฒด ํจ์ ์๋ด
โ @remarks + @example: ์์ธ ์ค๋ช ๊ณผ ์ค์ฉ ์์
๐ ๋งํฌ๋ค์ด ํ์ฉํ๊ธฐ
TSDoc ์ฃผ์ ์์์ ๋งํฌ๋ค์ด์ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฑด ์ ๋ง ํฐ ์ฅ์ ์ด์ผ. ํ ์คํธ๋ฅผ ๋ ์ฝ๊ธฐ ์ฝ๊ฒ ๋ง๋ค ์ ์๊ฑฐ๋ !/**
* ๋ณต์กํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํจ์์
๋๋ค.
*
* @remarks
* ์ด ํจ์๋ ๋ค์ ๋จ๊ณ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค:
*
* 1. **๊ฒ์ฆ**: ์
๋ ฅ ๋ฐ์ดํฐ์ ์ ํจ์ฑ ๊ฒ์ฌ
* 2. **๋ณํ**: ๋ฐ์ดํฐ๋ฅผ ๋ด๋ถ ํ์์ผ๋ก ๋ณํ
* 3. **์ฒ๋ฆฌ**: ๋น์ฆ๋์ค ๋ก์ง ์ ์ฉ
* 4. **๋ฐํ**: ๊ฒฐ๊ณผ ๋ฐ์ดํฐ ๋ฐํ
*
* > **์ค์**: ์ด ํจ์๋ ๋น๋๊ธฐ๋ก ๋์ํ๋ฏ๋ก ๋ฐ๋์ await๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
*
* ์ฑ๋ฅ ๊ณ ๋ ค์ฌํญ:
* - ๋์ฉ๋ ๋ฐ์ดํฐ(>10MB)๋ ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ ์ฌ์ฉํ์ธ์
* - ๋ณ๋ ฌ ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ฉด `processDataParallel()`์ ์ฌ์ฉํ์ธ์
*
* @param data - ์ฒ๋ฆฌํ ๋ฐ์ดํฐ
* @returns ์ฒ๋ฆฌ๋ ๊ฒฐ๊ณผ
*/
async function processData(data: RawData): Promise<ProcessedData> {
// ๊ตฌํ ์ฝ๋
}
๋ฆฌ์คํธ, ๊ฐ์กฐ, ์ธ์ฉ๊ตฌ ๋ฑ์ ์์ ๋กญ๊ฒ ์ฌ์ฉํ ์ ์์ด. ์ด๋ ๊ฒ ํ๋ฉด ๊ธด ์ค๋ช
๋ ๊ตฌ์กฐํ๋์ด์ ์ฝ๊ธฐ ํธํด์ ธ! ๐
๐ ๏ธ API ๋ฌธ์ ์๋ ์์ฑ ๋๊ตฌ๋ค
TSDoc ์ฃผ์์ ์ด์ฌํ ์์ฑํ๋ค๋ฉด, ์ด์ ์ด๊ฑธ ๋ฉ์ง ์น ๋ฌธ์๋ก ๋ณํํ ์ฐจ๋ก์ผ! ์ฌ๋ฌ ๋๊ตฌ๋ค์ด ์๋๋ฐ, ๊ฐ๊ฐ ํน์ง์ด ๋ฌ๋ผ. ํ๋ก์ ํธ์ ๋ง๋ ๋๊ตฌ๋ฅผ ์ ํํ๋ ๊ฒ ์ค์ํด. ๐จ๐ TypeDoc - ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ์ ํ
TypeDoc์ ํ์ ์คํฌ๋ฆฝํธ ํ๋ก์ ํธ๋ฅผ ์ํ ๋ฌธ์ ์์ฑ๊ธฐ ์ค ๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋ผ. JSDoc ์คํ์ผ์ ์ฃผ์์ ์ฝ์ด์ ์ ์ HTML ๋ฌธ์๋ฅผ ์์ฑํด์ค.๐ ๊ฐ๋ ฅํ ๊ฒ์: ์ ์ฒด ๋ฌธ์์์ ๋น ๋ฅด๊ฒ ๊ฒ์ ๊ฐ๋ฅ
๐ฏ ํ์ ์ ๋ณด: ํ์ ์คํฌ๋ฆฝํธ์ ํ์ ์ ๋ณด๋ฅผ ์๋ฒฝํ๊ฒ ํ์
๐ ํ๋ฌ๊ทธ์ธ ์์คํ : ๊ธฐ๋ฅ ํ์ฅ์ด ์ฌ์
โ๏ธ ์ปค์คํฐ๋ง์ด์ง: ํ ๋ง์ ๋ ์ด์์์ ์์ ๋กญ๊ฒ ๋ณ๊ฒฝ ๊ฐ๋ฅ
TypeDoc ์ค์น ๋ฐ ์ค์
TypeDoc์ ์์ํ๋ ๊ฑด ์ ๋ง ๊ฐ๋จํด. npm์ผ๋ก ์ค์นํ๊ณ ๊ฐ๋จํ ์ค์ ๋ง ํ๋ฉด ๋ผ.# TypeDoc ์ค์น
npm install --save-dev typedoc
# ๊ธฐ๋ณธ ๋ฌธ์ ์์ฑ
npx typedoc src/index.ts
ํ๋ก์ ํธ ๋ฃจํธ์ typedoc.json ํ์ผ์ ๋ง๋ค์ด์ ๋ ์ธ๋ฐํ๊ฒ ์ค์ ํ ์ ์์ด:
{
"entryPoints": ["src/index.ts"],
"out": "docs",
"name": "My Awesome Library",
"excludePrivate": true,
"excludeProtected": false,
"excludeExternals": true,
"readme": "README.md",
"theme": "default",
"includeVersion": true,
"categorizeByGroup": true,
"sort": ["source-order"]
}
package.json์ ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํ๋ฉด ๋ ํธํด:
{
"scripts": {
"docs": "typedoc",
"docs:watch": "typedoc --watch"
}
}
์ด์ npm run docs ๋ช
๋ น์ด ํ๋๋ก ๋ฌธ์๋ฅผ ์์ฑํ ์ ์์ด! ๐
๐ API Extractor + API Documenter
๋ง์ดํฌ๋ก์ํํธ์์ ๋ง๋ ๋๊ตฌ ์กฐํฉ์ด์ผ. ํนํ ๋๊ท๋ชจ ํ๋ก์ ํธ๋ ๋ชจ๋ ธ๋ ํฌ์์ ๊ฐ๋ ฅํด.๐ API ๋ ๋ฒจ ๊ด๋ฆฌ: public, beta, internal ๋ฑ์ผ๋ก ๊ตฌ๋ถ
๐ ๋ฒ๋ค ๋ถ์: .d.ts ํ์ผ์ ํ๋๋ก ๋กค์
โ ๊ฒ์ฆ: API ๋ณ๊ฒฝ์ฌํญ์ CI/CD์์ ์๋ ๊ฒ์ฆ
API Extractor ์ค์
# ์ค์น
npm install --save-dev @microsoft/api-extractor @microsoft/api-documenter
# ์ค์ ํ์ผ ์์ฑ
npx api-extractor init
์์ฑ๋ api-extractor.json์ ํ๋ก์ ํธ์ ๋ง๊ฒ ์์ ํด:
{
"mainEntryPointFilePath": "dist/index.d.ts",
"apiReport": {
"enabled": true,
"reportFolder": "temp"
},
"docModel": {
"enabled": true,
"apiJsonFilePath": "temp/<unscopedPackageName>.api.json"
},
"dtsRollup": {
"enabled": true,
"untrimmedFilePath": "dist/index.d.ts"
}
}
๋ฌธ์ ์์ฑ์ ๋ ๋จ๊ณ๋ก ์งํ๋ผ:
# 1. API ๋ชจ๋ธ ์ถ์ถ
npx api-extractor run --local
# 2. ๋ฌธ์ ์์ฑ
npx api-documenter markdown -i temp -o docs
๐ TSDoc ํ์ ์ง์ ์ฌ์ฉํ๊ธฐ
๋ ์ธ๋ฐํ ์ ์ด๊ฐ ํ์ํ๋ค๋ฉด TSDoc ํ์๋ฅผ ์ง์ ์ฌ์ฉํ ์๋ ์์ด. ์ปค์คํ ๋ฌธ์ ์์ฑ๊ธฐ๋ฅผ ๋ง๋ค ๋ ์ ์ฉํด.import { TSDocParser } from '@microsoft/tsdoc';
import * as ts from 'typescript';
const parser = new TSDocParser();
function extractDocumentation(sourceFile: ts.SourceFile) {
ts.forEachChild(sourceFile, node => {
if (ts.isFunctionDeclaration(node) && node.name) {
const jsDocComments = ts.getJSDocCommentsAndTags(node);
jsDocComments.forEach(comment => {
const text = comment.comment || '';
const parserContext = parser.parseString(text.toString());
console.log('Function:', node.name?.text);
console.log('Summary:', parserContext.docComment.summarySection);
});
}
});
}
์ด ๋ฐฉ๋ฒ์ ๋ณต์กํ์ง๋ง, ์์ ํ ์์ ๋๋ฅผ ์ ๊ณตํด. ํน๋ณํ ํ์์ ๋ฌธ์๊ฐ ํ์ํ๊ฑฐ๋, ๋ค๋ฅธ ์์คํ
๊ณผ ํตํฉํด์ผ ํ ๋ ์ ์ฉํด! ๐ฏ
API Extractor: ๋๊ท๋ชจ ํ๋ก์ ํธ, API ๋ฒ์ ๊ด๋ฆฌ๊ฐ ์ค์ํ ๋
์ปค์คํ ํ์: ํน์ํ ์๊ตฌ์ฌํญ์ด ์๊ฑฐ๋, ๊ธฐ์กด ์์คํ ๊ณผ ํตํฉํ ๋
๐ฏ ์ค์ ํ๋ก์ ํธ ์ ์ฉ ์ฌ๋ก
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋, ์ด์ ์ค์ ํ๋ก์ ํธ์ ์ด๋ป๊ฒ ์ ์ฉํ๋์ง ์ดํด๋ณด์! ์ค๋ฌด์์ ์์ฃผ ๋ง์ฃผ์น๋ ์ํฉ๋ค์ ์์ ๋ก ์ค๋นํ์ด. ๐ผ๐๏ธ ํด๋์ค ๋ฌธ์ํ
ํด๋์ค๋ ์ฌ๋ฌ ๋ฉ์๋์ ์์ฑ์ ๊ฐ์ง๊ณ ์์ด์ ๋ฌธ์ํ๊ฐ ์ข ๋ ๋ณต์กํด. ํ์ง๋ง ์ฒด๊ณ์ ์ผ๋ก ์ ๊ทผํ๋ฉด ์ด๋ ต์ง ์์!/**
* ์ฌ์ฉ์ ๊ด๋ฆฌ๋ฅผ ๋ด๋นํ๋ ์๋น์ค ํด๋์ค์
๋๋ค.
*
* @remarks
* ์ด ํด๋์ค๋ ์ฑ๊ธํค ํจํด์ผ๋ก ๊ตฌํ๋์ด ์์ต๋๋ค.
* `getInstance()` ๋ฉ์๋๋ฅผ ํตํด ์ธ์คํด์ค๋ฅผ ์ป์ด์ผ ํฉ๋๋ค.
*
* @example
* ```typescript
* const userService = UserService.getInstance();
* const user = await userService.createUser({
* name: 'Alice',
* email: 'alice@example.com'
* });
* ```
*/
export class UserService {
/**
* ์๋น์ค์ ์ฑ๊ธํค ์ธ์คํด์ค
* @internal
*/
private static instance: UserService;
/**
* ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์ ์ฅ์
*/
private readonly repository: UserRepository;
/**
* @internal
* ์์ฑ์๋ private์ผ๋ก ์ ์ธ๋์ด ์ธ๋ถ์์ ์ง์ ํธ์ถํ ์ ์์ต๋๋ค.
*/
private constructor() {
this.repository = new UserRepository();
}
/**
* UserService์ ์ฑ๊ธํค ์ธ์คํด์ค๋ฅผ ๋ฐํํฉ๋๋ค.
*
* @returns UserService ์ธ์คํด์ค
*/
public static getInstance(): UserService {
if (!UserService.instance) {
UserService.instance = new UserService();
}
return UserService.instance;
}
/**
* ์๋ก์ด ์ฌ์ฉ์๋ฅผ ์์ฑํฉ๋๋ค.
*
* @param userData - ์์ฑํ ์ฌ์ฉ์์ ์ ๋ณด
* @param userData.name - ์ฌ์ฉ์ ์ด๋ฆ (2-50์)
* @param userData.email - ์ด๋ฉ์ผ ์ฃผ์ (์ ํจํ ํ์์ด์ด์ผ ํจ)
* @param userData.age - ๋์ด (์ ํ์ฌํญ, 0-150)
* @returns ์์ฑ๋ ์ฌ์ฉ์ ๊ฐ์ฒด
*
* @throws {ValidationError} ์
๋ ฅ ๋ฐ์ดํฐ๊ฐ ์ ํจํ์ง ์์ ๋
* @throws {DuplicateError} ์ด๋ฏธ ์กด์ฌํ๋ ์ด๋ฉ์ผ์ผ ๋
*
* @example
* ```typescript
* const user = await userService.createUser({
* name: 'Bob',
* email: 'bob@example.com',
* age: 25
* });
* console.log(user.id); // ์์ฑ๋ ์ฌ์ฉ์ ID
* ```
*/
public async createUser(userData: CreateUserDto): Promise<User> {
// ๊ตฌํ ์ฝ๋
}
/**
* ID๋ก ์ฌ์ฉ์๋ฅผ ์กฐํํฉ๋๋ค.
*
* @param userId - ์กฐํํ ์ฌ์ฉ์์ ID
* @returns ์ฌ์ฉ์ ๊ฐ์ฒด ๋๋ null (์ฌ์ฉ์๊ฐ ์์ ๊ฒฝ์ฐ)
*
* @example
* ```typescript
* const user = await userService.getUserById('user-123');
* if (user) {
* console.log(user.name);
* } else {
* console.log('์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค');
* }
* ```
*/
public async getUserById(userId: string): Promise<User | null> {
// ๊ตฌํ ์ฝ๋
}
}
ํด๋์ค ๋ ๋ฒจ, ์์ฑ, ๋ฉ์๋ ๊ฐ๊ฐ์ ์ ์ ํ ๋ฌธ์๋ฅผ ์์ฑํ๋ ๊ฒ ํฌ์ธํธ์ผ. ๐ช
๐ง ์ธํฐํ์ด์ค์ ํ์ ๋ฌธ์ํ
ํ์ ์คํฌ๋ฆฝํธ์์ ์ธํฐํ์ด์ค์ ํ์ ์ ์ ๋ง ์ค์ํ์ง. ์ด๊ฒ๋ค๋ ์ ๋ฌธ์ํํด์ผ ํด!/**
* ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ํ๋ด๋ ์ธํฐํ์ด์ค์
๋๋ค.
*
* @remarks
* ์ด ์ธํฐํ์ด์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง์ 1:1๋ก ๋งคํ๋ฉ๋๋ค.
* ๋ชจ๋ ํ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋๋ ๊ฐ๊ณผ ๋์ผํ ํ์์ ์ ์งํฉ๋๋ค.
*/
export interface User {
/**
* ์ฌ์ฉ์์ ๊ณ ์ ์๋ณ์
* @remarks UUID v4 ํ์์ ์ฌ์ฉํฉ๋๋ค
*/
id: string;
/**
* ์ฌ์ฉ์ ์ด๋ฆ
* @remarks 2-50์ ์ฌ์ด์ฌ์ผ ํ๋ฉฐ, ํน์๋ฌธ์๋ ํ์ฉ๋์ง ์์ต๋๋ค
*/
name: string;
/**
* ์ด๋ฉ์ผ ์ฃผ์
* @remarks ์ ์ผํด์ผ ํ๋ฉฐ, ์ ํจํ ์ด๋ฉ์ผ ํ์์ด์ด์ผ ํฉ๋๋ค
*/
email: string;
/**
* ๊ณ์ ์์ฑ ์ผ์
* @remarks ISO 8601 ํ์์ ํ์์คํฌํ
*/
createdAt: Date;
/**
* ๋ง์ง๋ง ๋ก๊ทธ์ธ ์ผ์
* @remarks ํ ๋ฒ๋ ๋ก๊ทธ์ธํ์ง ์์ ๊ฒฝ์ฐ null
*/
lastLoginAt: Date | null;
}
/**
* ์ฌ์ฉ์ ์์ฑ ์ ํ์ํ ๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด์
๋๋ค.
*
* @remarks
* ์ด ํ์
์ {@link User} ์ธํฐํ์ด์ค์์ ์์คํ
์ด ์๋์ผ๋ก ์์ฑํ๋
* ํ๋๋ค(id, createdAt ๋ฑ)์ ์ ์ธํ ๊ฒ์
๋๋ค.
*/
export type CreateUserDto = Pick<User, 'name' | 'email'> & {
/**
* ์ด๊ธฐ ๋น๋ฐ๋ฒํธ
* @remarks ์ต์ 8์ ์ด์, ์๋ฌธ/์ซ์/ํน์๋ฌธ์ ์กฐํฉ
*/
password: string;
};
/**
* ํ์ด์ง๋ค์ด์
๊ฒฐ๊ณผ๋ฅผ ๋ํ๋ด๋ ์ ๋ค๋ฆญ ํ์
์
๋๋ค.
*
* @typeParam T - ํ์ด์ง๋ค์ด์
ํ ๋ฐ์ดํฐ์ ํ์
*
* @example
* ```typescript
* const result: PaginatedResult<User> = {
* items: [user1, user2, user3],
* total: 100,
* page: 1,
* pageSize: 10
* };
* ```
*/
export interface PaginatedResult<T> {
/** ํ์ฌ ํ์ด์ง์ ํญ๋ชฉ๋ค */
items: T[];
/** ์ ์ฒด ํญ๋ชฉ ์ */
total: number;
/** ํ์ฌ ํ์ด์ง ๋ฒํธ (1๋ถํฐ ์์) */
page: number;
/** ํ์ด์ง๋น ํญ๋ชฉ ์ */
pageSize: number;
/** ์ ์ฒด ํ์ด์ง ์ */
get totalPages(): number;
/** ๋ค์ ํ์ด์ง ์กด์ฌ ์ฌ๋ถ */
get hasNext(): boolean;
/** ์ด์ ํ์ด์ง ์กด์ฌ ์ฌ๋ถ */
get hasPrevious(): boolean;
}
๐จ React ์ปดํฌ๋ํธ ๋ฌธ์ํ
React๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ปดํฌ๋ํธ ๋ฌธ์ํ๋ ์ค์ํด. Props ์ธํฐํ์ด์ค๋ฅผ ์ ๋ฌธ์ํํ๋ฉด ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ด ์ปดํฌ๋ํธ๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ด!/**
* ์ฌ์ฉ์ ํ๋กํ ์นด๋ ์ปดํฌ๋ํธ์
๋๋ค.
*
* @remarks
* ์ด ์ปดํฌ๋ํธ๋ ์ฌ์ฉ์์ ๊ธฐ๋ณธ ์ ๋ณด๋ฅผ ์นด๋ ํํ๋ก ํ์ํฉ๋๋ค.
* ์๋ฐํ, ์ด๋ฆ, ์ด๋ฉ์ผ, ๊ทธ๋ฆฌ๊ณ ์ ํ์ ์ผ๋ก ์ถ๊ฐ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค ์ ์์ต๋๋ค.
*
* @example
* ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ:
* ```tsx
* <UserProfileCard
* user={currentUser}
* onEdit={() => handleEdit(currentUser.id)}
* />
* ```
*
* @example
* ์ถ๊ฐ ์ ๋ณด์ ํจ๊ป:
* ```tsx
* <UserProfileCard
* user={currentUser}
* showBio
* showJoinDate
* variant="detailed"
* />
* ```
*/
export const UserProfileCard: React.FC<UserProfileCardProps> = (props) => {
// ๊ตฌํ ์ฝ๋
};
/**
* UserProfileCard ์ปดํฌ๋ํธ์ Props ์ธํฐํ์ด์ค์
๋๋ค.
*/
export interface UserProfileCardProps {
/**
* ํ์ํ ์ฌ์ฉ์ ๊ฐ์ฒด
*/
user: User;
/**
* ์นด๋์ ํ์ ์คํ์ผ
* @defaultValue 'compact'
*/
variant?: 'compact' | 'detailed' | 'minimal';
/**
* ์ฌ์ฉ์ ์๊ฐ๋ฅผ ํ์ํ ์ง ์ฌ๋ถ
* @defaultValue false
*/
showBio?: boolean;
/**
* ๊ฐ์
๋ ์ง๋ฅผ ํ์ํ ์ง ์ฌ๋ถ
* @defaultValue false
*/
showJoinDate?: boolean;
/**
* ํธ์ง ๋ฒํผ ํด๋ฆญ ์ ํธ์ถ๋๋ ์ฝ๋ฐฑ
* @param userId - ํธ์งํ ์ฌ์ฉ์์ ID
*/
onEdit?: (userId: string) => void;
/**
* ์ญ์ ๋ฒํผ ํด๋ฆญ ์ ํธ์ถ๋๋ ์ฝ๋ฐฑ
* @param userId - ์ญ์ ํ ์ฌ์ฉ์์ ID
*/
onDelete?: (userId: string) => void;
/**
* ์ถ๊ฐ CSS ํด๋์ค๋ช
*/
className?: string;
/**
* ์ธ๋ผ์ธ ์คํ์ผ
*/
style?: React.CSSProperties;
}
React ์ปดํฌ๋ํธ๋ ํนํ @defaultValue ํ๊ทธ๋ฅผ ํ์ฉํด์ ๊ธฐ๋ณธ๊ฐ์ ๋ช
์ํ๋ ๊ฒ ์ข์. ์ฌ์ฉ์๊ฐ ์ด๋ค props๊ฐ ํ์์ด๊ณ ์ ํ์ธ์ง ์ฝ๊ฒ ์ ์ ์๊ฑฐ๋ ! โ๏ธ
๐ ์ ํธ๋ฆฌํฐ ํจ์ ๋ชจ์ ๋ฌธ์ํ
์ฌ๋ฌ ์ ํธ๋ฆฌํฐ ํจ์๋ฅผ ๋ชจ์๋์ ๋ชจ๋๋ ์ฒด๊ณ์ ์ผ๋ก ๋ฌธ์ํํด์ผ ํด./**
* ๋ฌธ์์ด ์ฒ๋ฆฌ ์ ํธ๋ฆฌํฐ ํจ์ ๋ชจ์์
๋๋ค.
*
* @remarks
* ์ด ๋ชจ๋์ ์ผ๋ฐ์ ์ธ ๋ฌธ์์ด ์กฐ์ ์์
์ ์ํ ํฌํผ ํจ์๋ค์ ์ ๊ณตํฉ๋๋ค.
* ๋ชจ๋ ํจ์๋ ์์ ํจ์๋ก ๊ตฌํ๋์ด ์์ผ๋ฉฐ, ์๋ณธ ๋ฌธ์์ด์ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค.
*
* @packageDocumentation
*/
/**
* ๋ฌธ์์ด์ ์ฒซ ๊ธ์๋ฅผ ๋๋ฌธ์๋ก ๋ณํํฉ๋๋ค.
*
* @param str - ๋ณํํ ๋ฌธ์์ด
* @returns ์ฒซ ๊ธ์๊ฐ ๋๋ฌธ์๋ก ๋ณํ๋ ๋ฌธ์์ด
*
* @example
* ```typescript
* capitalize('hello'); // 'Hello'
* capitalize('WORLD'); // 'WORLD'
* capitalize(''); // ''
* ```
*/
export function capitalize(str: string): string {
if (!str) return str;
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* ์นด๋ฉ์ผ์ด์ค ๋ฌธ์์ด์ ์ผ๋ฐฅ์ผ์ด์ค๋ก ๋ณํํฉ๋๋ค.
*
* @param str - ๋ณํํ ์นด๋ฉ์ผ์ด์ค ๋ฌธ์์ด
* @returns ์ผ๋ฐฅ์ผ์ด์ค๋ก ๋ณํ๋ ๋ฌธ์์ด
*
* @example
* ```typescript
* camelToKebab('userName'); // 'user-name'
* camelToKebab('getUserById'); // 'get-user-by-id'
* camelToKebab('API'); // 'a-p-i'
* ```
*/
export function camelToKebab(str: string): string {
return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
}
/**
* ๋ฌธ์์ด์ ์ง์ ๋ ๊ธธ์ด๋ก ์๋ฅด๊ณ ๋ง์ค์ํ๋ฅผ ์ถ๊ฐํฉ๋๋ค.
*
* @param str - ์๋ฅผ ๋ฌธ์์ด
* @param maxLength - ์ต๋ ๊ธธ์ด (๋ง์ค์ํ ํฌํจ)
* @param ellipsis - ๋ง์ค์ํ ๋ฌธ์ (๊ธฐ๋ณธ๊ฐ: '...')
* @returns ์๋ฆฐ ๋ฌธ์์ด
*
* @throws {Error} maxLength๊ฐ ellipsis ๊ธธ์ด๋ณด๋ค ์์ ๋
*
* @example
* ```typescript
* truncate('Hello World', 8); // 'Hello...'
* truncate('Short', 10); // 'Short'
* truncate('Long text here', 10, 'โฆ'); // 'Long textโฆ'
* ```
*/
export function truncate(
str: string,
maxLength: number,
ellipsis: string = '...'
): string {
if (maxLength < ellipsis.length) {
throw new Error('maxLength must be greater than ellipsis length');
}
if (str.length <= maxLength) return str;
return str.slice(0, maxLength - ellipsis.length) + ellipsis;
}
์ ํธ๋ฆฌํฐ ํจ์๋ ๋ค์ํ ์ํฉ์์ ์ฌ์ฉ๋๋๊น ์์ ๋ฅผ ์ฌ๋ฌ ๊ฐ ์ ๊ณตํ๋ ๊ฒ ์ข์! ๐ ๏ธ
โจ ๋ฌธ์ํ ๋ฒ ์คํธ ํ๋ํฐ์ค
์ด์ ์ค์ ํ๋ค์ ์๋ ค์ค๊ฒ! ์ด๋ฐ ์์น๋ค์ ๋ฐ๋ฅด๋ฉด ์ ๋ง ํ๋ฅญํ ๋ฌธ์๋ฅผ ๋ง๋ค ์ ์์ด. ๐๐ ์ผ๊ด์ฑ ์ ์งํ๊ธฐ
โ ํ๋ผ๋ฏธํฐ ์ค๋ช ์ ํญ์ ๋ช ์ฌ๊ตฌ๋ก ์์
โ ํจ์ ์ค๋ช ์ ๋์ฌ๋ก ์์ ("~ํฉ๋๋ค", "~๋ฅผ ๋ฐํํฉ๋๋ค")
โ ์์ ๋ ํญ์ ์คํ ๊ฐ๋ฅํ ์ฝ๋๋ก ์์ฑ
โ ์๋ฌ ์กฐ๊ฑด์ @throws ํ๊ทธ๋ก ๋ช ์
๐ฏ ๋ช ํํ๊ณ ๊ฐ๊ฒฐํ๊ฒ
๋ฌธ์๋ ๋ช ํํด์ผ ํด. ํ์ง๋ง ๋๋ฌด ์ฅํฉํ๋ฉด ์ ๋ผ. ํต์ฌ๋ง ๊ฐ๊ฒฐํ๊ฒ ์ ๋ฌํ๋ ๊ฒ ์ค์ํด.// โ ๋์ ์: ๋๋ฌด ์ฅํฉํจ
/**
* ์ด ํจ์๋ ์ฌ์ฉ์๊ฐ ์ ๊ณตํ ๋ ๊ฐ์ ์ซ์๋ฅผ ๋ฐ์์
* ๊ทธ๊ฒ๋ค์ ๋ํ ๋ค์์ ๊ทธ ๊ฒฐ๊ณผ๊ฐ์ ๋ฐํํ๋ ๊ธฐ๋ฅ์
* ์ํํฉ๋๋ค. ์ด ํจ์๋ ๋งค์ฐ ๊ฐ๋จํ์ง๋ง ์ ์ฉํ๊ฒ
* ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
*/
function add(a: number, b: number): number {
return a + b;
}
// โ
์ข์ ์: ๋ช
ํํ๊ณ ๊ฐ๊ฒฐํจ
/**
* ๋ ์ซ์๋ฅผ ๋ํฉ๋๋ค.
*
* @param a - ์ฒซ ๋ฒ์งธ ์ซ์
* @param b - ๋ ๋ฒ์งธ ์ซ์
* @returns ๋ ์ซ์์ ํฉ
*/
function add(a: number, b: number): number {
return a + b;
}
๐ ์์ ๋ ํ์!
์ฝ๋ ์์ ๋ ์ ๋ง ์ค์ํด. ํนํ ๋ณต์กํ API๋ ํจ์์ ๊ฒฝ์ฐ, ์์ ํ๋๊ฐ ๊ธด ์ค๋ช ๋ณด๋ค ํจ์ฌ ํจ๊ณผ์ ์ด์ผ.2๏ธโฃ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋ถํฐ ์์ํด
3๏ธโฃ ์ฃ์ง ์ผ์ด์ค๋ ์์ ๋ก ๋ณด์ฌ์ค
4๏ธโฃ ์์ ์ ์ฃผ์์ ๋ฌ์์ ์ค๋ช ์ ์ถ๊ฐํด
5๏ธโฃ ์ฌ๋ฌ ์๋๋ฆฌ์ค๋ฅผ ๋ณด์ฌ์ฃผ๋ ค๋ฉด @example์ ์ฌ๋ฌ ๋ฒ ์ฌ์ฉํด
๐ ๋ฌธ์๋ฅผ ์ต์ ์ํ๋ก ์ ์ง
์ฝ๋๊ฐ ๋ณ๊ฒฝ๋๋ฉด ๋ฌธ์๋ ํจ๊ป ์ ๋ฐ์ดํธํด์ผ ํด. ์ค๋๋ ๋ฌธ์๋ ์๋ ๊ฒ๋ณด๋ค ๋์ ์ ์์ด!// ์ฝ๋ ๋ฆฌ๋ทฐ ์ฒดํฌ๋ฆฌ์คํธ์ ๋ฌธ์ ์
๋ฐ์ดํธ ํฌํจ
// .github/pull_request_template.md
## ์ฒดํฌ๋ฆฌ์คํธ
- [ ] ์ฝ๋ ๋ณ๊ฒฝ์ฌํญ์ด ๋ฌธ์์ ๋ฐ์๋์๋์?
- [ ] ์๋ก์ด ๊ณต๊ฐ API์ TSDoc ์ฃผ์์ด ์ถ๊ฐ๋์๋์?
- [ ] ์์ ์ฝ๋๊ฐ ์ต์ API์ ํธํ๋๋์?
- [ ] ๋ณ๊ฒฝ๋ ํ๋ผ๋ฏธํฐ๋ ๋ฐํ๊ฐ์ด ๋ฌธ์ํ๋์๋์?
โ ๏ธ ์ค์ํ ์ ๋ณด๋ ๊ฐ์กฐํ๊ธฐ
ํน๋ณํ ์ฃผ์ํด์ผ ํ ์ฌํญ์ด๋ ์ค์ํ ์ ๋ณด๋ ๋์ ๋๊ฒ ํ์ํด์ผ ํด./**
* ๋์ฉ๋ ํ์ผ์ ์ฒ๋ฆฌํฉ๋๋ค.
*
* @remarks
* โ ๏ธ **์ค์**: ์ด ํจ์๋ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฒด ํ์ผ์ ๋ก๋ํฉ๋๋ค.
* 10MB ์ด์์ ํ์ผ์ `processLargeFileStream()`์ ์ฌ์ฉํ์ธ์.
*
* ๐ก **ํ**: ๋ณ๋ ฌ ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ฉด `processFileParallel()`์ ๊ณ ๋ คํ์ธ์.
*
* @param filePath - ์ฒ๋ฆฌํ ํ์ผ ๊ฒฝ๋ก
* @returns ์ฒ๋ฆฌ ๊ฒฐ๊ณผ
*
* @see {@link processLargeFileStream} - ๋์ฉ๋ ํ์ผ์ฉ ์คํธ๋ฆฌ๋ฐ ๋ฒ์
*/
function processFile(filePath: string): ProcessResult {
// ๊ตฌํ ์ฝ๋
}
๐ ๊ด๋ จ ํญ๋ชฉ ์ฐ๊ฒฐํ๊ธฐ
API ๋ฌธ์๋ ๋คํธ์ํฌ์ฒ๋ผ ์๋ก ์ฐ๊ฒฐ๋์ด ์์ด์ผ ํด. @see ํ๊ทธ๋ฅผ ์ ๊ทน ํ์ฉํด์ ๊ด๋ จ ํจ์๋ ํด๋์ค๋ฅผ ์ฐ๊ฒฐํด์ค./**
* ์ฌ์ฉ์๋ฅผ ์์ฑํฉ๋๋ค.
*
* @see {@link updateUser} - ์ฌ์ฉ์ ์ ๋ณด ์์
* @see {@link deleteUser} - ์ฌ์ฉ์ ์ญ์
* @see {@link getUserById} - ์ฌ์ฉ์ ์กฐํ
* @see {@link User} - ์ฌ์ฉ์ ์ธํฐํ์ด์ค
*/
function createUser(data: CreateUserDto): Promise<User> {
// ๊ตฌํ ์ฝ๋
}
๐จ ์ฝ๋ ์คํ์ผ ๊ฐ์ด๋ ํตํฉ
ESLint ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๋ฉด ๋ฌธ์ํ ๊ท์น์ ์๋์ผ๋ก ๊ฒ์ฌํ ์ ์์ด!# eslint-plugin-tsdoc ์ค์น
npm install --save-dev eslint-plugin-tsdoc
# .eslintrc.json ์ค์
{
"plugins": ["eslint-plugin-tsdoc"],
"rules": {
"tsdoc/syntax": "warn"
}
}
์ด๋ ๊ฒ ํ๋ฉด TSDoc ๋ฌธ๋ฒ ์ค๋ฅ๋ฅผ ์ฝ๋ ์์ฑ ์ค์ ๋ฐ๋ก ์ก์ ์ ์์ด! ๐ฏ
๐ CI/CD ํ์ดํ๋ผ์ธ์ ๋ฌธ์ ์์ฑ ํตํฉํ๊ธฐ
๋ฌธ์ ์์ฑ์ ์๋ํํ๋ฉด ํญ์ ์ต์ ๋ฌธ์๋ฅผ ์ ์งํ ์ ์์ด. CI/CD ํ์ดํ๋ผ์ธ์ ํตํฉํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์! โ๏ธ๐ฆ GitHub Actions๋ก ์๋ ๋ฐฐํฌ
GitHub Actions๋ฅผ ์ฌ์ฉํ๋ฉด ์ฝ๋๊ฐ ํธ์๋ ๋๋ง๋ค ์๋์ผ๋ก ๋ฌธ์๋ฅผ ์์ฑํ๊ณ ๋ฐฐํฌํ ์ ์์ด.# .github/workflows/docs.yml
name: Generate and Deploy Documentation
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
docs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Generate documentation
run: npm run docs
- name: Deploy to GitHub Pages
if: github.ref == 'refs/heads/main'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
cname: docs.yourproject.com
์ด์ main ๋ธ๋์น์ ํธ์ํ ๋๋ง๋ค ์๋์ผ๋ก ๋ฌธ์๊ฐ ์์ฑ๋๊ณ GitHub Pages์ ๋ฐฐํฌ๋ผ! ๐
๐ ๋ฌธ์ ํ์ง ๊ฒ์ฌ
๋ฌธ์๊ฐ ์ ๋๋ก ์์ฑ๋์๋์ง ์๋์ผ๋ก ๊ฒ์ฌํ๋ ๊ฒ๋ ์ค์ํด.# .github/workflows/docs-check.yml
name: Documentation Quality Check
on: [pull_request]
jobs:
check-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Check TSDoc syntax
run: npm run lint
- name: Generate docs (dry run)
run: npm run docs -- --dry-run
- name: Check for undocumented exports
run: |
npm run docs -- --validation.notDocumented
- name: Comment PR with results
uses: actions/github-script@v6
if: failure()
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'โ ๏ธ ๋ฌธ์ํ ๊ฒ์ฌ์ ์คํจํ์ต๋๋ค. ๋ชจ๋ ๊ณต๊ฐ API์ TSDoc ์ฃผ์์ ์ถ๊ฐํด์ฃผ์ธ์!'
})
๐ ๋ฌธ์ ์ปค๋ฒ๋ฆฌ์ง ์ธก์
์ผ๋ง๋ ๋ง์ ์ฝ๋๊ฐ ๋ฌธ์ํ๋์๋์ง ์ธก์ ํ๋ ๊ฒ๋ ์ ์ฉํด.// scripts/check-docs-coverage.ts
import * as ts from 'typescript';
import * as fs from 'fs';
interface CoverageStats {
total: number;
documented: number;
percentage: number;
}
function checkDocsCoverage(fileNames: string[]): CoverageStats {
const program = ts.createProgram(fileNames, {});
let total = 0;
let documented = 0;
for (const sourceFile of program.getSourceFiles()) {
if (sourceFile.fileName.includes('node_modules')) continue;
ts.forEachChild(sourceFile, node => {
if (isExportedDeclaration(node)) {
total++;
if (hasDocComment(node)) {
documented++;
}
}
});
}
return {
total,
documented,
percentage: total > 0 ? (documented / total) * 100 : 0
};
}
function isExportedDeclaration(node: ts.Node): boolean {
return (
(ts.isFunctionDeclaration(node) ||
ts.isClassDeclaration(node) ||
ts.isInterfaceDeclaration(node) ||
ts.isTypeAliasDeclaration(node)) &&
node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)
);
}
function hasDocComment(node: ts.Node): boolean {
const comments = ts.getLeadingCommentRanges(
node.getSourceFile().getFullText(),
node.getFullStart()
);
return comments?.some(c => c.kind === ts.SyntaxKind.MultiLineCommentTrivia) ?? false;
}
// ์คํ
const stats = checkDocsCoverage(['src/**/*.ts']);
console.log(`๋ฌธ์ํ ์ปค๋ฒ๋ฆฌ์ง: ${stats.percentage.toFixed(2)}%`);
console.log(`(${stats.documented}/${stats.total} ํญ๋ชฉ)`);
if (stats.percentage < 80) {
console.error('โ ๋ฌธ์ํ ์ปค๋ฒ๋ฆฌ์ง๊ฐ 80% ๋ฏธ๋ง์
๋๋ค!');
process.exit(1);
}
๐ ๋ค์ํ ํ๋ซํผ์ ๋ฐฐํฌ
์์ฑ๋ ๋ฌธ์๋ ์ฌ๋ฌ ํ๋ซํผ์ ๋ฐฐํฌํ ์ ์์ด:๐ Netlify/Vercel: ์๋ ๋น๋์ ํ๋ฆฌ๋ทฐ ๊ธฐ๋ฅ
๐ Read the Docs: ๋ฒ์ ๊ด๋ฆฌ์ ๊ฒ์ ๊ธฐ๋ฅ์ด ๊ฐ๋ ฅํด
๐ท Azure Static Web Apps: ์ํฐํ๋ผ์ด์ฆ๊ธ ํธ์คํ
โ๏ธ AWS S3 + CloudFront: ํ์ฅ์ฑ์ด ๋ฐ์ด๋
๐ ์ค๋ฌด์์ ๋ง์ฃผ์น๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ์ฑ
์ด๋ก ์ ์๋ฒฝํด ๋ณด์ด์ง๋ง, ์ค์ ๋ก ์ ์ฉํ๋ค ๋ณด๋ฉด ์ฌ๋ฌ ๋ฌธ์ ์ ๋ถ๋ชํ๊ฒ ๋ผ. ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๊ณต์ ํ ๊ฒ! ๐งโ ๋ฌธ์ 1: ๋ ๊ฑฐ์ ์ฝ๋ ๋ฌธ์ํ
์ด๋ฏธ ์์ฑ๋ ๋๋์ ์ฝ๋์ ๋ฌธ์๋ฅผ ์ถ๊ฐํ๋ ๊ฑด ์ ๋ง ํ๋ ์ผ์ด์ผ. ํ ๋ฒ์ ๋ค ํ๋ ค๊ณ ํ๋ฉด ์ง์ณ๋ฒ๋ฆฌ๊ธฐ ์ฌ์.2๏ธโฃ ์ ์ง์ ๊ฐ์ : ์ฝ๋๋ฅผ ์์ ํ ๋๋ง๋ค ๋ฌธ์๋ ํจ๊ป ์ถ๊ฐ
3๏ธโฃ ํ ๋ถ๋ด: ๊ฐ์ ๋ด๋น ๋ชจ๋์ ๋ฌธ์ํ ์ฑ ์
4๏ธโฃ ์๋ํ ๋๊ตฌ: AI ๋๊ตฌ๋ก ์ด์ ์์ฑ ํ ๊ฒํ
// ์ฐ์ ์์ ๊ธฐ๋ฐ ๋ฌธ์ํ ์ฒดํฌ๋ฆฌ์คํธ
// docs-priority.md
## Phase 1: ํต์ฌ ๊ณต๊ฐ API (1์ฃผ์ฐจ)
- [ ] User ๊ด๋ จ ํจ์๋ค
- [ ] Authentication ๋ชจ๋
- [ ] ์ฃผ์ ์ ํธ๋ฆฌํฐ ํจ์
## Phase 2: ์์ฃผ ์ฌ์ฉ๋๋ ๋ด๋ถ API (2์ฃผ์ฐจ)
- [ ] Database ํฌํผ
- [ ] Validation ํจ์๋ค
- [ ] Error ํธ๋ค๋ง
## Phase 3: ๋๋จธ์ง ์ฝ๋ (3-4์ฃผ์ฐจ)
- [ ] ํ
์คํธ ์ ํธ๋ฆฌํฐ
- [ ] ์ค์ ๊ด๋ จ ์ฝ๋
- [ ] ๊ธฐํ ํฌํผ ํจ์๋ค
โ ๋ฌธ์ 2: ๋ฌธ์์ ์ฝ๋์ ๋ถ์ผ์น
์ฝ๋๋ ๋ณ๊ฒฝํ๋๋ฐ ๋ฌธ์๋ฅผ ์ ๋ฐ์ดํธํ๋ ๊ฑธ ๊น๋นกํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์. ์ด๋ ๊ฒ ๋๋ฉด ๋ฌธ์๊ฐ ์คํ๋ ค ํผ๋์ ์ค ์ ์์ด.๐ค ์๋ ๊ฒ์ฆ: CI์์ ๋ฌธ์ ์์ฑ ์คํจ ์ ๋น๋ ์คํจ
๐ ๋ฆฐํฐ ๊ท์น: ๊ณต๊ฐ API๋ ๋ฐ๋์ ๋ฌธ์ํ ๊ฐ์
๐ฅ ํ์ด ํ๋ก๊ทธ๋๋ฐ: ์ฝ๋์ ๋ฌธ์๋ฅผ ํจ๊ป ์์ฑ
// .eslintrc.json - ๋ฌธ์ํ ๊ฐ์
{
"rules": {
"jsdoc/require-jsdoc": ["error", {
"require": {
"FunctionDeclaration": true,
"MethodDefinition": true,
"ClassDeclaration": true,
"ArrowFunctionExpression": false,
"FunctionExpression": false
},
"publicOnly": true
}],
"jsdoc/require-param": "error",
"jsdoc/require-returns": "error",
"jsdoc/require-description": "warn"
}
}
โ ๋ฌธ์ 3: ๊ณผ๋ํ ๋ฌธ์ํ
๋ชจ๋ ๊ฑธ ๋ฌธ์ํํ๋ ค๋ค ๋ณด๋ฉด ์คํ๋ ค ํต์ฌ์ด ํ๋ ค์ง ์ ์์ด. ๋๋ฌด ์๋ช ํ ๊ฒ๊น์ง ์ค๋ช ํ๋ฉด ๋ฌธ์๊ฐ ์ง์ ๋ถํด์ ธ./**
* ์ซ์๋ฅผ 1 ์ฆ๊ฐ์ํต๋๋ค.
* @param n - ์ฆ๊ฐ์ํฌ ์ซ์
* @returns 1์ด ์ฆ๊ฐ๋ ์ซ์
* @example
* increment(5) // 6์ ๋ฐํํฉ๋๋ค
*/
function increment(n: number): number {
return n + 1;
}
์ด๋ฐ ๊ฑด ๋๋ฌด ์๋ช
ํด์ ๋ฌธ์๊ฐ ๋ถํ์ํด!
- โ ๊ณต๊ฐ API๋ ๋ฐ๋์ ๋ฌธ์ํ
- โ ๋ณต์กํ ๋ก์ง์ด๋ ์๊ณ ๋ฆฌ์ฆ์ ์์ธํ ์ค๋ช
- โ ์์์น ๋ชปํ ๋์์ด๋ ์ ์ฝ์ฌํญ์ ๋ช ์
- โ ์ฝ๋๋ง ๋ด๋ ๋ช ํํ ๊ฒ์ ์๋ต ๊ฐ๋ฅ
- โ ๋ด๋ถ ํฌํผ ํจ์๋ ๊ฐ๋จํ๋ง
โ ๋ฌธ์ 4: ๋ค๊ตญ์ด ๋ฌธ์ ์ง์
๊ธ๋ก๋ฒ ํ๋ก์ ํธ๋ผ๋ฉด ์ฌ๋ฌ ์ธ์ด๋ก ๋ฌธ์๋ฅผ ์ ๊ณตํด์ผ ํ ์๋ ์์ด./**
* Creates a new user account.
* ์๋ก์ด ์ฌ์ฉ์ ๊ณ์ ์ ์์ฑํฉ๋๋ค.
*
* @param userData - User information / ์ฌ์ฉ์ ์ ๋ณด
* @param userData.email - Email address / ์ด๋ฉ์ผ ์ฃผ์
* @param userData.name - User name / ์ฌ์ฉ์ ์ด๋ฆ
* @returns Created user object / ์์ฑ๋ ์ฌ์ฉ์ ๊ฐ์ฒด
*
* @example
* ```typescript
* const user = await createUser({
* email: 'user@example.com',
* name: 'John Doe'
* });
* ```
*/
async function createUser(userData: CreateUserDto): Promise<User> {
// Implementation
}
ํ์ง๋ง ์ด ๋ฐฉ๋ฒ์ ์ ์ง๋ณด์๊ฐ ์ด๋ ค์. ๋ ๋์ ๋ฐฉ๋ฒ์ ๋ฌธ์ ์์ฑ ๋๊ตฌ์์ ๋ค๊ตญ์ด๋ฅผ ์ง์ํ๋ ๊ฑฐ์ผ.
โ ๋ฌธ์ 5: ์ฑ๋ฅ ๋ฌธ์ํ
ํจ์์ ์๊ฐ ๋ณต์ก๋๋ ๊ณต๊ฐ ๋ณต์ก๋๋ ์ค์ํ ์ ๋ณด์ผ. ํนํ ์ฑ๋ฅ์ด ์ค์ํ ํจ์๋ผ๋ฉด ๋ฐ๋์ ๋ช ์ํด์ผ ํด./**
* ๋ฐฐ์ด์์ ํน์ ๊ฐ์ ์ฐพ์ต๋๋ค.
*
* @remarks
* **์๊ฐ ๋ณต์ก๋**: O(n) - ์ ํ ํ์<br>
* **๊ณต๊ฐ ๋ณต์ก๋**: O(1) - ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ์์
*
* ๋๋์ ๋ฐ์ดํฐ์์ ๋น ๋ฅธ ๊ฒ์์ด ํ์ํ๋ฉด
* {@link binarySearch}๋ฅผ ์ฌ์ฉํ์ธ์ (O(log n)).
*
* @param array - ๊ฒ์ํ ๋ฐฐ์ด
* @param target - ์ฐพ์ ๊ฐ
* @returns ๊ฐ์ ์ธ๋ฑ์ค, ์์ผ๋ฉด -1
*/
function linearSearch<T>(array: T[], target: T): number {
for (let i = 0; i < array.length; i++) {
if (array[i] === target) return i;
}
return -1;
}
์ฑ๋ฅ ํน์ฑ์ ๋ฌธ์ํํ๋ฉด ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ด ์ ์ ํ ํจ์๋ฅผ ์ ํํ๋ ๋ฐ ๋์์ด ๋ผ! โก
๐ ๋ณด๋์ค: ์ ์ฉํ ๋๊ตฌ์ ๋ฆฌ์์ค
๋ฌธ์ํ๋ฅผ ๋ ์ฝ๊ณ ํจ์จ์ ์ผ๋ก ๋ง๋ค์ด์ฃผ๋ ๋๊ตฌ๋ค์ ์๊ฐํ ๊ฒ! ๐ ๏ธ๐ VS Code ํ์ฅ ํ๋ก๊ทธ๋จ
| ํ์ฅ ํ๋ก๊ทธ๋จ | ๊ธฐ๋ฅ | ์ถ์ฒ๋ |
|---|---|---|
| Document This | ์๋์ผ๋ก TSDoc ํ ํ๋ฆฟ ์์ฑ | โญโญโญโญโญ |
| Better Comments | ์ฃผ์์ ์์์ผ๋ก ๊ตฌ๋ถ | โญโญโญโญ |
| TypeDoc Generator | VS Code์์ ๋ฐ๋ก ๋ฌธ์ ์์ฑ | โญโญโญโญ |
| TSDoc Comment | TSDoc ๋ฌธ๋ฒ ํ์ด๋ผ์ดํ | โญโญโญโญโญ |
๐ ํ์ต ๋ฆฌ์์ค
๐ TypeDoc ๊ฐ์ด๋: https://typedoc.org/guides/overview
๐ Microsoft API Extractor: https://api-extractor.com
๐ก JSDoc ์ฐธ๊ณ : https://jsdoc.app (TSDoc์ ๊ธฐ๋ฐ)
๐ค AI ๋๊ตฌ ํ์ฉ
์ต๊ทผ์๋ AI๊ฐ ๋ฌธ์ ์์ฑ์ ๋์์ค ์ ์์ด. ํ์ง๋ง ์์ ํ ์์กดํ๋ฉด ์ ๋๊ณ , ๋ฐ๋์ ๊ฒํ ํ๊ณ ์์ ํด์ผ ํด!// GitHub Copilot์ ํ์ฉํ ๋ฌธ์ ์์ฑ
// ํจ์ ์๊ทธ๋์ฒ๋ฅผ ์์ฑํ๊ณ /** ๋ฅผ ์
๋ ฅํ๋ฉด
// Copilot์ด ์๋์ผ๋ก ๋ฌธ์๋ฅผ ์ ์ํด์ค
function processUserData(
userId: string,
options: ProcessOptions
): Promise<ProcessResult> {
// Copilot์ด ์ ์๊ทธ๋์ฒ๋ฅผ ๋ณด๊ณ
// ์ ์ ํ TSDoc ์ฃผ์์ ์ ์ํด์ค
}
๐จ ๋ฌธ์ ํ ๋ง ์ปค์คํฐ๋ง์ด์ง
TypeDoc์ ๊ธฐ๋ณธ ํ ๋ง๋ ์ข์ง๋ง, ํ๋ก์ ํธ์ ๋ง๊ฒ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ด.// typedoc.json
{
"theme": "default",
"customCss": "./docs-theme/custom.css",
"customJs": "./docs-theme/custom.js",
"favicon": "./docs-theme/favicon.ico",
"logo": "./docs-theme/logo.png",
"hideGenerator": true,
"footerDate": true
}
์ปค์คํ
CSS๋ก ๋ธ๋๋ ์ปฌ๋ฌ๋ฅผ ์ ์ฉํ๋ฉด ๋ ์ ๋ฌธ์ ์ผ๋ก ๋ณด์ฌ! ๐จ
๐ ๋ฌธ์ ๋ถ์ ๋๊ตฌ
๋ฌธ์์ ํ์ง์ ์ธก์ ํ๊ณ ๊ฐ์ ์ ์ ์ฐพ์์ฃผ๋ ๋๊ตฌ๋ค๋ ์์ด.# documentation.js - ๋ฌธ์ ํ์ง ๋ถ์
npm install -g documentation
# ๋ฌธ์ ์ปค๋ฒ๋ฆฌ์ง ๋ฆฌํฌํธ ์์ฑ
documentation lint src/**/*.ts
# ๋ฌธ์ ํ์ง ์ ์ ํ์ธ
documentation coverage src/**/*.ts
๐ฏ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์! ์ฌ๊ธฐ๊น์ง ์ ๋ง ๊ธด ์ฌ์ ์ด์์ด. ๐ ํ์ ์คํฌ๋ฆฝํธ ๋ฌธ์ํ์ TSDoc์ ๋ํด ๋ง์ ๊ฑธ ๋ฐฐ์ ์ง? ๋ฌธ์ํ๋ ์ฒ์์๋ ๊ท์ฐฎ๊ฒ ๋๊ปด์ง ์ ์์ด. ํ์ง๋ง ์๊ฐ์ด ์ง๋๋ฉด์ ๊ทธ ๊ฐ์น๋ฅผ ํ์คํ ๋๋ผ๊ฒ ๋ ๊ฑฐ์ผ. ํนํ ํ ํ๋ก์ ํธ๋ ์คํ์์ค ํ๋ก์ ํธ์์๋ ์ ๋ง ์ค์ํด!๐ท๏ธ ํ๊ทธ ํ์ฉ: @param, @returns, @example ๋ฑ์ ์ ๊ทน ํ์ฉ
๐ ๏ธ ์๋ํ: TypeDoc์ด๋ API Extractor๋ก ๋ฌธ์ ์๋ ์์ฑ
โ๏ธ CI/CD ํตํฉ: ๋ฌธ์ ์์ฑ์ ์๋ํ ํ์ดํ๋ผ์ธ์ ํฌํจ
โจ ํ์ง ์ ์ง: ๋ฆฐํฐ์ ๊ฒ์ฆ ๋๊ตฌ๋ก ๋ฌธ์ ํ์ง ๊ด๋ฆฌ
๐ฏ ์ค์ฉ์ฑ: ๊ณผ๋ํ์ง ์๊ฒ, ํ์ํ ๋งํผ๋ง ๋ฌธ์ํ
2. ๊ฐ์ฅ ์ค์ํ ๊ณต๊ฐ API 3๊ฐ ๋ฌธ์ํํ๊ธฐ
3. CI/CD์ ๋ฌธ์ ์์ฑ ์ถ๊ฐํ๊ธฐ
4. ํ์๋ค๊ณผ ๋ฌธ์ํ ๊ฐ์ด๋๋ผ์ธ ๋ง๋ค๊ธฐ
5. ์ ๊ธฐ์ ์ผ๋ก ๋ฌธ์ ํ์ง ๋ฆฌ๋ทฐํ๊ธฐ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.