인프런 타입스크립트 기초를 통해 공부중이며 제로초님의 유료강좌입니다.

코드를 통으로 가져오지는 않겠습니다.(내가 글을 쓰면서 복습하는게 목적이기때문에 필요한 부분만)

 

타입스크립트에 익숙하지않다면 자바스크립트로 먼저 코드를 작성하고 그 후에 타입스크립트로 변환하도록하자.

 

타입스크립트 (Typescript)

 

오 드디어 강의가 거의 끝이 나 보인다.!!!!

강의보고 이해하고 글한번 적고,, 다른것도 하다보니 되게 오래걸렸다.

다보고나면 뭐 하나 만들어보고 간단히 강의 훑고 react랑 typesctipt 같이 써봐야지!

 

진짜 의식의 흐름대로 글을쓰다보니 1회차부터 보니까 ㅋㅋㅋ 내가 헷갈림..ㅎㅎ

나중에는 공식문서보면서 좀 제대로 알아봐야겠다.

 

Typescript를 지원하는 패키지, 아닌 패키지

일단 typescript로 제작된 패키지도 있고 아닌애들도 있는데, redux같은 경우에는 typescript로 되어있어서 가져다쓰기 좋다고한다. 

redux git에 가서 보면 이렇게 Typescript로 작성되었다는 것을 알 수 있다.

 

DefinitelyTyped

만약 내가 쓰려는 패키지가 Typescript로 작성되어있지 않다면 definitelyTyped를 이용하자.

https://github.com/DefinitelyTyped/DefinitelyTyped

 

이 레퍼지토리는 많은 사람들이 모여서 지원안하는 패키지의 type을 만들어둔 곳이라고한다.

공식적으로 지원하는 것이 없을 경우 여기서 찾아보면된다고!

유명하지 않은 패키지같은 경우에는 없을 수도 있다고 한다.

types 폴더에서 react나 jQuery들을 확인할 수 있다.

install하는 방법은 cmd 창에 @types/ 로 시작하면된다.

npm i @types/jquery

 

Triple Slash 

패키지를 다운로드 받고 나면 d.ts파일에 아래와 같은 코드를 확인할 수 있는 경우가 있다.

이 경우는 다른 패키지를 참조하는 것을 나타내는데, 속성 값으로는 types와 path가 있다.

types에는 패키지의 이름을 적을 수 있고, path에는 경로를 적을 수 있다.

아래 코드와 같이 적혀있는 경우에는 symbol-observable을 참조하고 있다는 뜻이다.

/// <reference types="symbol-observable" />

왜 import를 안하냐고 할 수 있는데, import도 가능하나 다른 패키지를 참조할때는 저렇게 사용한다고 한다.

보통 프로젝트 코드가 아닌 라이브러리를 만들때 사용한다고 한다.

 

 

Namespace

export as namespace d3;

namespace는 export한 것들을 d3라는 네임으로 묶어주는 것을 뜻한다.

export as namespace d3;

export * from 'd3-array';
export * from 'd3-axis';

아래와 같이 되어있다면 d3-array에 export한 함수중에 max라는 함수가 있다면 아래와 같이 접근 할 수 있다.

d3.max

 

 

import * as 

import하자마자 export한다는 뜻이다.

import * as d3 from 'd3';

 

 

declare

타입이 없는 것을 새로 선언할 경우에 사용할 수 있다.

types라는 폴더를 생성하고 그 아래 d.ts파일을 생성하여 아래와 같이 can-use-dom 패키지의 d.ts파일을 생성해 줄 수 있다. 

// d.ts 파일
declare module 'can-use-dom'{
	const canUseDOM: boolean;
    export default canUseDOM;
}
// config 파일
{
	"compilerOptions" : {
    	"strict" : true,
        "lib" : ["EX5", "ES2015", "ES2017", "ES2018", "ES2019"],
        "typeRoots" : ["./types", "./node_modules/@types"]
    },
    "exclude" : ["*.js"]
}

types는 내가 만든 파일이 들어있는 폴더의 경로이며 node_modules는 definitelyTyped에서 받은 d.ts파일들이 있다.

 

아래와 같이 다양한 작업을 할 수 있다.

전역 객체 선언

export{}
declare global{
	interface Window{
    	//...
    }
    
    interface Error{
    	//...
    }
}

export{}를 한 이유는 글로벌인 경우 external모듈이어야하기 때문에(규칙) export를 사용하여 꼼수로 에러가 안나도록한다.

글로벌 객체를 확장하기 위해서는 external, ambient 모듈이어야한다.

아래처럼 ambient 모듈로 만들어도된다. namespace, interface를 통해 express의 request를 확장할 수 있다.

declare module 'connect-flash'{
	global {
    	namespace Express{
        	interface Request{
            	//...
            }
        }
    }
}

import express = require('express');

(모듈관련해서는 좀 더 자세히 알아봐야할 듯 싶다)

 

 

잘못된 d.ts파일이라면?

1.먼저 패키지 d.ts파일을 install해서 복사해준다.

// 예시는 connect-flash 모듈
npm i @types/connect-flash

2.패키지를 제거한다.

npm rm @types/connect-flash

3.내가 작성하려는 d.ts파일을 모아둔 폴더에 빈 파일을 생성하여 붙여넣는다.

4.잘못된 부분만 수정한다.

 

 

d.ts파일 옵션 - 라이브러리 만들때 사용하는방법

// config 파일
{
	"compilerOptions" : {
    	"strict" : true,
        "lib" : ["EX5", "ES2015", "ES2017", "ES2018", "ES2019"],
        "typeRoots" : ["./types", "./node_modules/@types"],
        
        // 옵션추가
        "declaration" : true,
        "declarationDir" : "./types"
    },
    "exclude" : ["*.js"]
}

그 후 npx tsc 하게되면 declarationDir 경로에 d.ts파일을 자동으로 생성해준다.

 

 

intersection

& 이것을 말한다.

둘다 만족하는 것을 뜻한다.

type A = string & number;

예제

interface A { 
	a : true
};

interface B{
	b : false
};

const c: A & B = {
	a: true,
    b: false
}

interface나 type aliases에서 사용할 수 있다.

interface A { 
	a : true
};

interface B{
	b : false
};

type C = {
	c : false
}

const d: A & B & C= {
	a: true,
    b: false,
    c: false
}

|는 하나만 만족해도된다.

interface A { 
	a : true
};

interface B{
	b : false
};

const c: A | Bㅌ= {
	a: true,
    b: true
}

코드의 중복을 막고 각각의 변수를 재사용하기 위해 좋다.

 

 

call, bind, apply

타입추론이 잘 안되는 메서드들이다.

타입스크립트가 업데이트되면서 새로운 옵션이 생겼다고 한다.

// config 파일
{
	"compilerOptions" : {
    	"strict" : true,
        
		// 옵션 추가
        "strictBindCallApply" : true,	
        
        "lib" : ["EX5", "ES2015", "ES2017", "ES2018", "ES2019"],
        "typeRoots" : ["./types", "./node_modules/@types"],
        "declaration" : true,
        "declarationDir" : "./types"
    },
    "exclude" : ["*.js"]
}

타입스크립트가 엄격해진다고한다.

 

 

TS유틸리티

Partial

// interface의 일부만 가져다가 사용할 때 사용한다. 
interface A {
	a: 'a',
    b: 123
}

const a: A = {
	a: 'a',
    b: 123
};

// b가없어도 에러가 나지 않는다.
const b: Partial<A> = {
	a: 'a'
}

Readonly

// 하나하나 넣어주면 너무 비효율적
interface A{
	readonly a: 'a',
    readonly b: 'b',
    readonly c: 'c'
};

// Readonly
interface B{
	a: 'a'
};

const b: Readonly<B> = {
	a: 'a'
}

그 외에 공식문서보고 쭉 읽어보자.

pick, omit 등..

 

 

데코레이터

클래스나 클래스의 기능을 수정할 수 있다.

중복되는 코드가 생겼을때 함수를 하나 만들어서 사용할 수 있다.

아직 정식 문법이 아니어서 옵션 값을 추가해준다.

// config 파일
{
	"compilerOptions" : {
    	"strict" : true,
        "strictBindCallApply" : true,	
        "lib" : ["EX5", "ES2015", "ES2017", "ES2018", "ES2019"],
        "typeRoots" : ["./types", "./node_modules/@types"],
        
        // 옵션 추가
        "experimentalDecorators" : true,
        
        "declaration" : true,
        "declarationDir" : "./types"
    },
    "exclude" : ["*.js"]
}

위에 적으면 클래스 데코레이터

메서드 옆에적으면 메서드 데코레이터라고 한다.

프로퍼티에 적으면 프로퍼티 데코레이터, 파라미터 옆이면 파라미터 데코레이터가 된다고 한다.

@makeGender
class Person{}

class Person{
	@validate title : string
}
// typeof Person안하고 Person만 적으면 인스턴스가 되버려서 꼭 typeof Person해야한다.
function makeGender(target: typeof Person){
	
    // 원본을 인자로 받아서 새로운 것을 extends 시켜서 내보낸다.
    return class extends target{
    	//...
    }
}

@makeGender
class Person{
	//....
}

@makeGender
class Person2{
	//....
}

 

데코레이터의 각각의 위치에 따라서 매개변수가 달라진다고 한다.

3번째 인자 값이 달라진다.

// 클래스 데코레이터
function readonly(target: any, key: any, descriptor: propertyDescriptor){
	//....
}

// 파라미터 데코레이터
function readonly(target: any, key: any, index: number){
	//....
}

 

 

Q&A 타입스크립트는 왜써요?

노드로 개발할 경우 서버가 죽는 경우가 생긴다.

보통어이없는 실수가 대부분이다.

타입스크립트는 코드 작성 시 에디터에서 한번 걸러주고 빌드시 두번 걸러줘서 안정성이 올라갈 수 있다.

자바스크립트는 런타입에서 오류가 나야 알 수 있다.

퍼포먼스가 좋아지는 일은 없다. 

안좋아지는 일도 없다 빌드하는 시간이 걸리기는 하지만 컴파일된 코드를 런타임에서 실행하기 때문에 퍼포먼스에는 이상이 없다.

 

 

인프런 타입스크립트 기초를 통해 공부중이며 제로초님의 유료강좌입니다.

코드를 통으로 가져오지는 않겠습니다.(내가 글을 쓰면서 복습하는게 목적이기때문에 필요한 부분만)

 

타입스크립트에 익숙하지않다면 자바스크립트로 먼저 코드를 작성하고 그 후에 타입스크립트로 변환하도록하자.

 

타입스크립트 (Typescript)

 

클래스와 인터페이스를 사용할때 언제 써야할까?

만약 내가 작업할 때 new키워드를 쓰지 않고 상속의 구현만 할것이라면 인터페이스를 사용해도 무방하다.

(실제 사용은 클래스에서 extends 하는 방식으로 하고 구현만 할거라면 인터페이스 implements해준다.

interface Example{
    (a: number, b: number) : number;
}

const ex: Example = (a,b) => a + b;

함수나 클래스는 할당되는 문법이 따로 있기 때문에 보통 객체에서 인터페이스를 많이 쓴다고 한다.(취향일수도)

 

 

인터페이스로 객체 타입을 선언

interface Example{
    add: (a: number, b: number) => number;
}

const ex: Example = {
    add: (a,b) => {
        return a + b;
    }
}

 

 

제네릭(Generic)

인터페이스에서의 제네릭

// 인터페이스
interface Test<T>{
	//...
}

// 클래스
class Test<T> implements Example{ 
	//...
}

// 함수
function Test<T>(arr: T[], callback: (item: T) => void): void{
	//...
}

 

 

 

타입 여러개를 더하기하는 함수를 만들고 싶다고 했을때 어떻게 해야할까?

(아래 예제에 string 타입을 더하고 있는 함수하나가 있고 string과 number타입을 모두 포함하는 함수를 만들고 싶다. 그리고 같은 타입끼리만 더해져야한다.)

function add(a: string, b: string): string{
    return a + b;
}

두번 선언할 것인가?

자바스크립트에서는 같은 함수를 두 번 선언할 수 없다.

// (X)
function add(a: string, b: string): string{
    return a + b;
}

function add(a: number, b: number): number{
    return a + b;
}

이렇게 선언한다면 에러가 난다. 그렇다면 or 연산자를 써서 해결해야할까?

function add(a: number | string, b: number | string): number | string{
    return a + b;
}

타입 두개를 추가하는데에는 만족했지만 해당 타입끼리 더해야한다는 요구조건을 만족할 수 없다.

아래와 같이 string과 number의 더하기도 허용한다.

add(1 + 'abc');

이때 해결할 수 있는 방법은 제네릭을 사용하는것이다.

제네릭은 임의의 변수를 만들어서 함수를 생성하고 나중에 이 함수를 사용할때 타입값을 입력받는 것이다.

 

함수로는 생성할 수 없고 인터페이스를 통해 생성해야한다.

// (X)
function add<T>(a: T, b: T): T{
    return a + b;
}

// (O)
interface obj<T>{
    add: (a: T, b: T) => T;
}

 

인터페이스 선언 시에 T라는 임의의 타입을 작성해 둠으로써 여유롭게 선언한다.

(T는 임의의 이름이다. 다른 이름도 상관 없다)

// T라는 타입을 제네릭으로 바꾼다.
interface obj<T>{
    add: (a: T, b: T) => T;
}

// 인터페이스를 사용할때 타입을 정해준다.
// <T>에 number를 넣게되는 것
const a: obj<number> = {
    add: (a, b) => (a + b);
};

// <T>에 string을 넣게되는 것
const b: obj<string> = {
    add: (a, b) => (a + b);
};

a.add(1, 2);
b.add('a', 'b');

 

addEventListener를 사용할 때 보통 아래와 같이 사용하는데, 

타입스크립트가 어떤식으로 동작하는지 알기 위해 lib.dom.d.ts파일을 확인해보자.

document.addEvenListener<'submit'>('submit', () => {});

lib.dom.d.ts에는 <K extends keyof ...... 라고 적혀있다.

이때 저 K가 제네릭이다.

 

실제 내가 넣었던 'submit'이 K로 들어가게된다.

그리고 extends keyof DocumentEventMap을 확인한 뒤 DocumentEventMap -> ... -> 순서대로 따라가다보면 GlobalEventHandlerEventHandlersEventMap까지 다다를 수 있는데,

내부에 key를 확인해보면 된다.

key에 없는 값을 입력할 경우 타입스크립트에서는 유추할 수 없다.

만약 타입이 현저히 다를 경우 두번째 documentEventListener(type: string.... 선언에 맞춰간다.

(둘 중에 적합한 것을 찾는다)

이것을 function overloading이라고 한다.

 

제네릭에서 extends란

클래스에서 extends는 상속을 말하는데 타입스크립트에서 extends는 제한이라는 뜻이다.

즉 타입에 대한 제한을 두는 것이다.

아래 예시는 boolean을 타입으로 넣는 경우이다.

interface obj<T>{
    add: (a: T, b: T) => T;
}

const a: obj<boolean> = {
    add: (a, b) => (a + b);
};

boolean타입을 더한다니? 이렇듯 아무거나 타입을 넣게되면 원하는 결과가 나오지 않기 때문에 제한을 둔다.

만약 extends string을 넣는다면 string과 string을 extends한 타입들만 선언할 수 있도록 하는 것이다.

interface obj<T extends string>{
    add: (a: T, b: T) => T;
}

여기서 number를 넣게되면 에러가 난다.

 

아래처럼 작성된 경우 K는 HTMLElementEventMap에서 keyof로 제한을 두겠다는 의미다.

첫번째 인수로는 key로 포함된 이벤트만 들어와야 에러가 나지 않는다.

document.addEventListener<'submit'>('submit', 

 

제네릭에 기본 값을 넣을 수 있다.

// K가 넘겨오는 타입 extends는 제약사항
// HTMLElementTagNameMap에서 key를 제약으로둔다.
// = 'div'는 기본 값
createElement<K extends keyof HTMLElementTagNameMap = 'div'>(.....

 

+ 제네릭 안에 제네릭도 들어갈 수 있다.

 

 

lib.dom.d.ts파일의 find를 확인해보자.

이것은 인터페이스 내부에 들어있다.

아래와 같이 선언했을때

Array<T>에서 먼저 타입을 받고 있다.

그리고 Array로 'a', 'b', 'c'를 삽입했기 때문에 item의 타입이 string인 것을 타입스크립트는 유추할 수 있다.

['a','b','c'].forEach((item) => {});

 

만약 오만가지 타입을 다 넣는다면 any가 될까?

아니다. 

// item : string | number | boolean | undefined | null 형식으로 유추한다.
['a',1,true, undefined, null].forEach((item) => {});

 

빈 배열을 삽입할 경우에는 never가 된다.

[].find((item) => {
    //......
});

 

아래 find에는 predicate라는 텍스트가 있는데

true, false를 반환하는 콜백함수인 경우에 predicate라 부른다.  

 

forEach를 구현하여 제네릭에 대해 더 자세히 알아보자.

function forEach<T>(arr: T[], callback: (item: T) => void): void{
    for(let i: number = 0; i < arr.length; i++){
        callback(arr[i]);
    }
}

// 사용할때 제네릭 넣기
// item이 자동으로 유추된다.
// forEach 선언할 때 item의 타입에도 T를 넣었기 때문에 유추가 되는 부분이다.
forEach<string>(['a', 'b', 'c'], (item) => {
     //........
});

 

일단 타입스크립트에서 타입추론되는 부분이 있다면 그 중에 제네릭일 확률이 있고 콜백함수에서 타입추론되는 경우 제네릭일 확률이 높다고한다.

 

 

 

 

인프런 타입스크립트  기초를 통해 공부중이며 제로초님의 유료강좌입니다.

코드를 통으로 가져오지는 않겠습니다.(내가 글을 쓰면서 복습하는게 목적이기때문에 필요한 부분만)

 

타입스크립트 (Typescript)

 

as const;

변수를 상수처럼 쓰고 싶다.

타입스크립트 전용 문법인 as const; 를 뒤에 붙이면 된다.

let str = 'haha' as const;
let arr = [true, 2, '3'] as const; 

변수에 마우스를 올렸을때 

let arr:readonly [true, 2,, '3'] 이라고 뜨는데, 여기서 새로운 타입 readonly를 볼 수 있다.

as const;로 선언할 경우 let이어도 재 정의시에 에러가 난다.

그렇다면 const로 선언하면 되지 않나? 라고 하는데,

const str = 'haha' as const;
const arr = [true, 2, '3'] as const;

이때 객체의 단점을 확인할 수 있다.

오브젝트 자체의 값을 변경할 수 는 없지만 오브젝트의 프로퍼티에 접근하여 값을 변경할 수 있기 때문이다.

const obj = { a : 'b' };

// (X)
obj = 'haha';

// 문제 발생
obj.a = 'a';

따라서 이런 경우 as const;를 선언해주면 배열이나 객체의 내부 값들도 상수로 만들 수 있다.

const obj = { a : 'b' } as const;

 

 

객체 object 타입 선언하기

object의 타입이 많이 존재할 수 있기 때문에 타입을 단순히 object라고 선언하지 않는다.

// (X)
const obj : object = { a : 'b' };

타입을 만들어서 선언해준다. 이때부터 코드가 길어져서 가독성이 안좋아진다.

const obj: {a : string } = { a : 'b' };

// (O)
obj.a = 'a';

// (X)
obj.a = 3;

그리고 타입을 선언했을때 아래와 같이 선언한 a, b에 대한 값을 모두 충족시켜야 에러가 발생하지 않는다.

// (X)
const obj: { a : string, b : number } = { a : 'b' };

// (O)
const obj: { a : string, b : number } = { a : 'b', b : 3 };

여기서 만약 값이 있을수도 있고 없을 수도 없다면 어떻게 할까?

왜냐하면 프로그래밍을 하다보면 나중에 값을 삽입하게 되는 경우가 있기 때문인데,

이때는 물음표를 넣어준다.

*중복코드의 느낌이 나는 경우가 생기기때문에 나중에는 인터페이스나 타입으로 빼게 된다고 한다.

const obj: { a : string, b? : number } = { a : 'b', b : 3 };

 

 

 

타입스크립트의 타입 enum

enum Color { Red, Green, Blue }
let c: Color.Green;

js로 컴파일하게되면 아래와 같이 나온다.

(function (Color) {
	Color[Color["Red"] = 0] = "Red";
	Color[Color["Green"] = 1] = "Green";
	Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));

enum은 각각의 단어에 숫자를 넣거나 반대로 넣어도 성립되게 만들어준다.

Color[0] === 'Red';
Color['Red'] === 0;

 

 

물음표의 역할

자바스크립트에서 물음표는 삼항연산자에 쓰인다.

타입스크립트에서는 옵션체이닝때 사용하는데, ?. 라는 것도 있다.

?.은 삼항연산자와 구분하기 위함이라고 한다.

const obj: { a : string, b? : number } = { a : 'b', b : 3 };
const a = abc?.name;

 

 

null과 undefined, void

자바스크립트의 null은 object인데, 이건 자바스크립트의 버그이므로 타입스크립트에서는 null의 타입은 null로 체크한다.

undefined는 undefined의 타입을 가지고 있다 void 0의 타입도 undefined이다.

const n = null;
const n = undefined;
const n = void 0;

 

 

함수에서 사용하기

함수에서 타입스크립트는 변수, 매개변수, 리턴 값에 타입을 붙일 수 있다.

// (매개변수) : 리턴 값에 대한 타입
function f(a: number, b: number): number | string {
    return a + b;
}

리턴 값이 없는 함수는 return undefined가 생략된 것이지만 이럴경우 타입을 void로 적으면 된다.

undefined로 작성하면 에러가 난다.

function f(a: number, b: number): void {
   console.log(a, b);
}

 

 

고차함수

함수가 고차함수를 리턴하는 경우 리턴되는 값의 타입을 작성하면된다.

함수의 타입은 리턴 값의 타입 자리에 적어준다.

// 함수 자체를 타입으로 쓸때
// (c: string) => number 함수 파라미터의 타입값과 함께 리턴 값을 적어줘야한다.
function f(a: number, b: number): (c: string) => number {
    return(c: string) => {
        return c;
    }
}

// 함수를 선언할때
function f(p: number): number{
    // ....
}

함수형 프로그래밍할때 고차함수를 많이 사용하는데, 

이러한 경우 때문에 가독성이 점점 안좋아지는 것이다.

function add(a: number, b: number): (c: string) => (d: string) => boolean {
    return (c: string) => {
        return (d: string) => {
            return false;
        }
    }
}

 

 

객체

자바스크립트는 타입이라는 개념이 없다.

따라서 오버로딩이 없다. (흉내내기일 뿐)

이때 타입스크립트는 타입이 존재하기 때문에 오버로딩이 구현된다.

// obj2의 타입
const obj2: {a: (b: number) => string} = {
    a(b: number){
        return 'hello';
    }
}

// 매개변수가 있어도되고 없어도 될때, 오버로딩일 경우 물음표를 추가해준다.
const obj2: {a: (b?: number) => string} = {
    a(b?: number){
        return 'hello';
    }
}

// 둘다 호출해도 에러가 안난다. 
// 만약 물음표를 추가하지 않았으면 에러가 난다.
obj.a();
obj.a(3);

 

 

 

들어가기전에...

신규프로젝트가 있어서 산출물 작업때 JSDoc을 사용하려고 생각했는데,

프로젝트에서 JSDoc을 사용하지 않게되어 ㅎㅎ 개인적으로 정리하여 작성합니다.

그냥 이런저런 주석이 있구나 생각을 정리하는 유익한 시간이었습니다. 

 

*프로젝트에서 사용할만하거나 많이 사용되는 주석 위주로 작성하였으며 출처는 jsdoc문서입니다.

전체 주석에 대하여 궁금하면 https://jsdoc.app/  jsdoc 문서를 참고해주세요.

 

JSDoc란

Javasript 소스코드 파일에 주석을 달기위해 사용되는 마크업언어입니다.

JSDoc에 포함하는 주석을 사용하여 코드를 작성하고 인터페이스를 설명하는 문서를 생성할 수 있습니다.

전체 이미지 / docdash 템플릿

 

JSDoc 설치 / 사용법

0. 프로젝트 설정

JSDoc을 설정하려는 프로젝트 폴더에서 진행한다.

// cmd
npm init -y

 

1. 설치

// cmd
npm i --save-dev jsdoc

테마 설치

https://github.com/clenemt/docdash

// cmd
npm install docdash

 

2. 해당하는 파일 문서화(jsdoc.conf 사용 시 파일에 작성된 incloude에 적힌 경로로 적용됨)

- 단일 파일

단일 파일

// cmd
jsdoc index.js

 

- 단일 폴더내에 복수 파일

단일 폴더내에 복수파일

// cmd
jsdoc ./js

 

- 복수 파일

복수 파일

//cmd
jsdoc ./js main.js

 

3. jsdoc.conf 설정하기

루트 폴더의 위치에서 jsdoc.conf 파일 생성 후 아래 코드 삽입

1. include의 경로 수정할 것 (해당파일 경로)

2. template 테마 docdash사용 시 docdash다운로드 받아야함 (template는 테마)

jsdoc.conf 생성

// jsdoc.conf
{
  "source" : {
    "include" : "./assets/js/layerPopup.js",
    "includePattern" : ".js$"
  },
  "plugins" : [
      "plugins/markdown"
  ],
  "opts" : {
    "template" : "node_modules/docdash",
    "encoding" : "utf8",
    "destination" : "./docs",
    "recurse" : true,
    "verbose" : true
  },
  "templates" : {
    "cleverLinks" : false,
    "monospaceLinks" : false,
    "default" : {
        "outputSourceFiles" : false
    },
    "docdash" : {
      "static" : false,
      "sort" : true
    }
  }
}

 

4. 결과물

// cmd
jsdoc -c jsdoc.conf README.md

- jsdoc -c : 참조하는 (설정파일 configuration)

- jsdoc.conf : 설정파일

- README.md : readme.md 파일 포함하여 생성

 

 

자동 생성된 docs 폴더에서 index.html 확인

(자동생성되는 폴더의 기본 네이밍은 out이지만 jsdoc.conf 파일에서 docs로 변경하였습니다.)

docs 폴더 구조

 

주석 설명

문서 설명 주석

문서를 설명하는 주석으로 문서 상단에 입력하여 문서를 설명한다.

 

@author

작성자 식별, 이메일 주소가 있으면 이름 뒤에 꺽쇠괄호로 작성한다.

이메일주소 입력 시에 출력화면에 메일주소가 노출되지는 않으나 앞에 작성한 텍스트(작성자)를 클릭할 경우 mailto 태그처럼 이메일 주소를 식별해준다.

문법

// @author <name>
// @author <name> [<emailAddress>]

예제

/**
 * @author Jane Smith <jsmith@example.com>
 */

function MyClass() {}

출력화면

출력 이미지

 

@version  

라이브러리 버전 정보

문법

// @version 버전정보

예제

/**
 * Solves equations of the form a * x = b. Returns the value
 * of x.
 * @version 1.2.3
 */

function solver(a, b) {
	return b / a;
}

출력화면

출력 이미지

 

@copyright 

파일 개요, 설명에 대한 저작권 정보 (w.@file)

문법

// @copyright <some copyright text>

 

@file (@fileoverview, @overview)

파일에 대한 설명

문법

// @file <some text>

예제

/**
 * @file This is my cool script.
 * @copyright Michael Mathews 2011
 */

출력화면

출력 이미지

 

@license

소프트웨어 라이센스

표준오픈소스 라이브러리 식별자(identifier) 입력  https://spdx.org/licenses/

문법

// @license <identifier>​

예제

/**
 * Utility functions for the foo package.
 * @module foo/util
 * @license Apache-2.0
 */

예제2

독립라이센스가 있는 파일

/**
 * @license
 * Copyright (c) 2015 Example Corporation Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

출력화면

출력 이미지

 

함수에 사용할 수 있는 주석

 

@this

해당 함수내부의 this가 참조하는 것을 표시

문법

// @this <namePath>

예제

/** @constructor */
function Greeter(name) {
	setName.apply(this, name);
}

/** @this Greeter */
function setName(name) {
  /** document me */
  this.name = name;
}

출력화면

출력 이미지

 

@constant (@const) 

상수를 표시

문법

// @constant [<type> <name>]

예시

/**
 * @constant
 * @type {string}
 * @default
 */
const RED = 'FF0000';

/** @constant {number} */
var ONE = 1;

 

@description (@desc)

설명을 표시

문법

// @description <some description>

예제

첫번째 줄일때에는 생략가능

/**
 * Add two numbers.
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
function add(a, b) {
	return a + b;
}

예제2

첫번째 줄이 아닐때

/**
 * @param {number} a
 * @param {number} b
 * @returns {number}
 * @description Add two numbers.
 */
function add(a, b) {
	return a + b;
}

출력화면

출력 이미지

 

@throws (@exception)

메소드에 의해 발생된 오류나 예외사항을 표시

단일 주석에 두번 포함하지말 것

문법

// @throws free-form description
// @throws {<type>}
// @throws {<type>} free-form description

예제

/**
 * @throws {DivideByZero} Argument x must be non-zero.
 */

function baz(x) {}

출력화면

출력 이미지

 

@param (@arg, @argument)

함수에 전달받은 인자 값의 이름

유형 및 설명을 표시

문법

// @param  <someParamName>
// @param {<type>} <someParamName>
// @param {<type>} <some description>

예제

단일 속성

/**
 * @param {string} somebody - Somebody's name.
 */
function sayHello(somebody) {
	alert('Hello ' + somebody);
}

예제2

복수 속성

/**
 * @param {(string|string[])} [somebody=John Doe] - Somebody's name, or an array of names.
 */
 function sayHello(somebody) {
 	if (!somebody) {
    	somebody = 'John Doe';
    } else if (Array.isArray(somebody)) {
    	somebody = somebody.join(', ');
    }
    
    alert('Hello ' + somebody);
}

예제3

파라미터에 속성이 있을때

/**
 * Assign the project to an employee.
 * @param {Object} employee - The employee who is responsible for the project.
 * @param {string} employee.name - The name of the employee.
 * @param {string} employee.department - The employee's department.
 */
Project.prototype.assign = function(employee) {
	// ...
};

예제4

파라미터가 배열, 속성이 있을경우

/**
 * Assign the project to a list of employees.
 * @param {Object[]} employees - The employees who are responsible for the project.
 * @param {string} employees[].name - The name of an employee.
 * @param {string} employees[].department - The employee's department.
 */
Project.prototype.assign = function(employees) {
	// ...
};

출력화면

출력 이미지

 

@requires 

필요한 모듈이 있음을 표현

문법

// @requires <someModuleName>

예제

/**
 * This class requires the modules {@link module:xyzcorp/helper} and
 * {@link module:xyzcorp/helper.ShinyWidget#polish}.
 * @class
 * @requires module:xyzcorp/helper
 * @requires xyzcorp/helper.ShinyWidget#polish
*/
function Widgetizer() {}

출력화면

출력 이미지

 

@callback

콜백으로 받은 인자 및 반환 값에 대한 정보 제공

문법

// @callback <namepath>

예제

클래스 별

/**
 * @class
 */
function Requester() {}

/**
 * Send a request.
 * @param {Requester~requestCallback} cb - The callback that handles the response.
 */
Requester.prototype.send = function(cb) {
	// code
};

/**
 * This callback is displayed as part of the Requester class.
 * @callback Requester~requestCallback
 * @param {number} responseCode
 * @param {string} responseMessage
 */

예제2

글로벌

/**
 * @class
 */
function Requester() {}

/**
 * Send a request.
 * @param {requestCallback} cb - The callback that handles the response.
 */
Requester.prototype.send = function(cb) {
	// code
};

/**
 * This callback is displayed as a global member.
 * @callback requestCallback
 * @param {number} responseCode
 * @param {string} responseMessage
*/

 

@todo

해야하거나, 완료해야할 작업이 필요할때 표시

단일 주석에 두번 사용 금지

문법

// @todo text describing thing to do.

예제

/**
 * @todo Write the documentation.
 * @todo Implement this function.
 */
function foo() {
	// write me
}

출력화면

출력 이미지

 

@return (@returns)

함수가 반환하는 값을 표시

문법

// @returns [{type}] [description]

예제

/**
 * Returns the sum of a and b
 * @param {number} a
 * @param {number} b
 * @returns {number} Sum of a and b
 */
function sum(a, b) {
	return a + b;
}

출력화면

출력이미지

 

@see

연관성 있는 문서나 리소스 참조함을 표시

{@link} 와 같이 사용 가능

문법

// @see <namepath>
// @see <text>

예제

/**
 * Both of these will link to the bar function.
 * @see {@link bar}
 * @see bar
 */
function foo() {}

// Use the inline {@link} tag to include a link within a free-form description.
/**
 * @see {@link foo} for further information.
 * @see {@link http://github.com|GitHub}
 */
function bar() {}

출력화면

출력이미지

 

@link ({@linkcode}, {@linkplain})

namepath 또는 url에 대한 링크 생성

문법

// {@link namepathOrURL}
// [link text]{@link namepathOrURL}
// {@link namepathOrURL|link text}
// {@link namepathOrURL link text (after the first space)}

예제

/*
 ** See {@link MyClass} and [MyClass's foo property]{@link MyClass#foo}.
 * Also, check out {@link http://www.google.com|Google} and
 * {@link https://github.com GitHub}.
 */
function myFunction() {}

 

@since

클래스, 메서드 등이 특정 버전에서 추가되었을때 사용

문법

// @since <versionDescription>

예제

/**
 * Provides access to user information.
 * @since 1.0.1
 */
function UserRecord() {}

출력화면

출력이미지

 

이벤트

@fires | @event | @listens

 

@fires (@emits)

메소드가 호출 될 때

지정된 유형의 이벤트를 발생시킬 수 있음을 표현

문법

// @fires <className>#<eventName>
// @fires <className>#[event:]<eventName>

 

@event

특정 이벤트를 정의

문법

// @event <className>#<eventName>
// @event <className>#[event:]<eventName>

 

@listens

지정된 이벤트를 수신하는 것을 표현

문법

// @listens <eventName>

예제

define('hurler', [], function () {
  /**
   * Event reporting that a snowball has been hurled.
   *
   * @event module:hurler~snowball
   * @property {number} velocity - The snowball's velocity, in meters per second.
   */

  /**
   * Snowball-hurling module.
   *
   * @module hurler
   */
  var exports = {
    /**
     * Attack an innocent (or guilty) person with a snowball.
     *
     * @method
     * @fires module:hurler~snowball
     */
    attack: function () {
    	this.emit('snowball', { velocity: 10 });
    }
  }; 
  
  return exports;  
});
  
define('playground/monitor', [], function () {
    /**
     * Keeps an eye out for snowball-throwers.
     *
     * @module playground/monitor
     */
    var exports = {
      /**
       * Report the throwing of a snowball.
       *
       * @method
       * @param {module:hurler~event:snowball} e - A snowball event.
       * @listens module:hurler~event:snowball
       */
      reportThrowage: function (e) {
          this.log('snowball thrown: velocity ' + e.velocity);
      }
    }; 
    
    return exports;
});

 

@example

예제 제공

<caption>태그를 @example 뒤에 사용하여 캡션기능 제공 가능

문법

// @example 
// @exmple <caption>captionText</caption>

예제

/**
 * Solves equations of the form a * x = b
 * @example
 * // returns 2
 * @example <caption>Example usage of method1.</caption>
 * // returns 2
 * globalNS.method1(5, 10);
 * @returns {Number} Returns the value of x for the equation.
 */
globalNS.method1 = function (a, b) {
	return b / a;
};

출력화면

출력이미지

 

@global

역함수 표현, 로컬에 작성되고 전역에 할당된 태그 사용에 유용

예제

(function() {
  /** @global */
  var foo = 'hello foo';
  this.foo = foo;
}).apply(window);

출력화면

출력 이미지

 

@namespace

네임스페이스 프로그래밍 시 객체 표현

문법

// @namespace [[{<type>}] <SomeName>]

예제

/**
 * My namespace.
 * @namespace
 */
var MyNamespace = {
  /** documented as MyNamespace.foo */
  foo: function() {},
  
  /** documented as MyNamespace.bar */
  bar: 1
};

예제2

/**
 * A namespace.
 * @namespace MyNamespace
 */

/**
 * A function in MyNamespace (MyNamespace.myFunction).
 * @function myFunction
 * @memberof MyNamespace
 */

예제3

/** @namespace window */
/**
 * Shorthand for the alert function.
 * Refer to it as {@link window."!"} (note the double quotes).
 */
window["!"] = function(msg) { 
	alert(msg); 
};

 

@inner

네임스페이스 태그의 부모-자녀 참조

예제

/** @namespace */
var MyNamespace = {
  /**
   * foo is now MyNamespace~foo rather than MyNamespace.foo.
   * @inner
   */
  foo: 1
};

 

@alias

네임스페이스 태그의 멤버 참조처리

내부 함수 내에 클래스 정의할 때 유용하다

예제

/** @namespace */
var Apple = {};(function(ns) {

  /**
   * @namespace
   * @alias Apple.Core
   */
  var core = {}; 

  /** Documented as Apple.Core.seed */
  core.seed = function() {}; 
  ns.Core = core;

})(Apple);

 

클래스를 설명하는 주석

class 키워드를 사용했거나 생성자를 통해 개발한 경우 해당할 수 있습니다.

 

@class (@constructor)

함수 생성자로 표시

문법

// @class [<type> <name>]

예제

/**
 * Creates a new Person.
 * @class
 */
function Person(){}
var p = new Person();

출력화면

출력이미지

 

 

@classdesc

함수 생성자 설명

@class가 선언되어있어야 한다.

문법

// @classdesc <some description>

예제

/**
 * This is a description of the MyClass constructor function. 
 * @class
 * @classdesc This is a description of the MyClass class.
 */
function MyClass() {}

출력화면

출력 이미지

 

@constructs

객체리터럴를 사용하여 클래스를 정의했을때 해당 멤버 표시

@lends와 사용할 수 있다.

문법

// @constructs [<name>]

예제

makeClass('Menu',
  /**
   * @constructs Menu
   * @param items
   */
  function (items){},
  {
    /** @memberof Menu# */
    show: function(){}
  }
);

// @lends와 사용
var Person = makeClass(
  /** @lends Person.prototype */
  {
    /** @constructs */
    initialize: function(name) {
        this.name = name;
    },
    /** Describe me. */
    say: function(message) {
        return this.name + " says: " + message;
    }
  }
);

출력화면

출력이미지

 

@lends 

함수 생성자의 멤버

문법

// @lends <namepath>

예제

/** @class */
var Person = makeClass(
  /** @lends Person */
  {
    /**
     * Create a `Person` instance.
     * @param {string} name - The person's name.
     */
    initialize: function(name) {
        this.name = name;
    },
    /**
     * Say something.
     * @param {string} message - The message to say.
     * @returns {string} The complete message.
     */
    say: function(message) {
        return this.name + " says: " + message;
    }
  }
);

 

@abstract (@virtual)

상속하는 객체에서 재정의하는 멤버 식별(오버라이딩 객체)

예제

/**
 * Generic dairy product.
 * @constructor
 */
function DairyProduct() {}

/**
 * Check whether the dairy product is solid at room temperature.
 * @abstract
 * @return {boolean}
 */
DairyProduct.prototype.isSolid = function() {
	throw new Error('must be implemented by subclass!');
};

/**
 * Cool, refreshing milk.
 * @constructor
 * @augments DairyProduct
 */
function Milk() {}

/**
 * Check whether milk is solid at room temperature.
 * @return {boolean} Always returns false.
 */
Milk.prototype.isSolid = function() {
	return false;
};

출력화면

출력이미지

 

@augments (@extends)

클래스 기반이나 프로토타입 기반에서 상속을 나타내고 상위 객체를 추가함

문법

// @augments <namepath>

예제

단일상속

/**
 * @constructor
 */
function Animal() {
	/** Is this animal alive? */
	this.alive = true;
}

/**
 * @constructor
 * @augments Animal
 */
function Duck() {}
Duck.prototype = new Animal();

예제2

다중 상속

/**
 * Abstract class for things that can fly.
 * @class
 */
function Flyable() {
	this.canFly = true;
}

/** Take off. */
Flyable.prototype.takeOff = function() {
	// ...
};

/**
 * Abstract class representing a bird.
 * @class
 */
function Bird(canFly) {
	this.canFly = canFly;
}

/** Spread your wings and fly, if possible. */
Bird.prototype.takeOff = function() {
  if (this.canFly) {
    this._spreadWings()
    ._run()
    ._flapWings();
  }
};

/**
 * Class representing a duck.
 * @class
 * @augments Flyable
 * @augments Bird
 */
function Duck() {} // Described in the docs as "Spread your wings and fly, if possible."
Duck.prototype.takeOff = function() {
	// ...
};

 

주석 정리 후 모듈에 적용을 해봤는데, 아직 정확한 개념이 박히지 않아서 오래걸리는군요 ㅎㅎ..

개발 시 주석을 잘 달기 위해 다른 문서화 도구들도 봐야할 것 같습니다.

 

 

 

+ Recent posts