타입스크립트에서 Dayjs 플러그인 만드는 방법

Dayjs 플러그인 만들기 도전

날짜 정보를 YYYY-MM-DD HH:mm:ssYYYY-MM-DD 포맷의 문자열로 출력할 때가 자주 있다.
그리고 반대로 YYYY-MM-DD HH:mm:ssYYYY-MM-DD 포맷의 문자열을 인자값으로 받아서 파싱한 다음에 날짜 정보를 얻어 올 때도 자주 있다.

그럴 때마다 다음과 같이 일일이 포맷을 작성해줘야 하는데

import * as dayjs from 'dayjs';

dayjs().format('YYYY-MM-DD HH:mm:ss');                      // 2022-02-05 12:42:50
dayjs().format('YYYY-MM-DD');                               // 2022-02-05
dayjs('2022-02-05 12:42:50', 'YYYY-MM-DD HH:mm:ss', true);  // 2022-02-05T12:42:50+09:00
dayjs('2022-02-05', 'YYYY-MM-DD', true);                    // 2022-02-05T00:00:00+09:00

매우 번거롭다.

포맷을 enum 타입 값으로 선언하면 번거로움이 줄어들긴 하지만, 임포트해야 하는 모듈이 늘어난다는 단점이 있다.

// dateTimeFormat.ts

export enum DateTimeFormat {
  YMDHMS = 'YYYY-MM-DD HH:mm:ss',
  YMD = 'YYYY-MM-DD',
}

// test.ts

import * as dayjs from 'dayjs';
import { DateTimeFormat } from './dateTimeFormat';

dayjs().format(DateTimeFormat.YMDHMS);                      // 2022-02-05 12:42:50
dayjs().format(DateTimeFormat.YMD);                         // 2022-02-05
dayjs('2022-02-05 12:42:50', DateTimeFormat.YMDHMS, true);  // 2022-02-05T12:42:50+09:00
dayjs('2022-02-05', DateTimeFormat.YMD, true);              // 2022-02-05T00:00:00+09:00

Dayjs 플러그인 기능을 사용해서 아래와 같이 코드를 작성할 수 있도록 만들어보기로 했다.

import * as dayjs from 'dayjs';

dayjs().toYMDHMS();                       // 2022-02-05 12:42:50
dayjs().toYMD();                          // 2022-02-05
dayjs.fromYMDHMS('2022-02-05 12:42:50');  // 2022-02-05T12:42:50+09:00
dayjs.fromYMD('2022-02-05');              // 2022-02-05T00:00:00+09:00

공식 문서에 나와 있는 그대로 Dayjs 플러그인 개발

Dayjs 공식 문서에 있는 템플릿 코드를 참조해서 플러그인을 만들었다.

// myDayjsPlugin.ts

import * as dayjs from 'dayjs';

export default (option, dayjsClass, dayjsFactory) => {
  /* 날짜와 시간을 'YYYY-MM-DD HH:mm:ss' 포맷의 문자열로 반환합니다.
  * ex)
  * dayjs().toYMDHMS()                           // 2022-02-05 12:42:50
  */ 
  dayjsClass.prototype.toYMDHMS = function(): string {
  	return this.format('YYYY-MM-DD HH:mm:ss');
  }
  
  /* 날짜를 'YYYY-MM-DD' 형식의 문자열로 반환합니다.
  * ex)
  * dayjs().toYMD()                              // 2022-02-05
  */
  dayjsClass.prototype.toYMD = function(): string {
    return this.format('YYYY-MM-DD');
  }
  
  /* 'YYYY-MM-DD HH:mm:ss' 포맷의 문자열을 파싱해서 Dayjs 클래스 인스턴스를 생성합니다.
  * ex)
  * dayjs.fromYMDHMS('2022-02-05 12:42:50');     // 2022-02-05T12:42:50+09:00
  */
  dayjsFactory.fromYMDHMS = function(datetime: string): dayjs.Dayjs {
    return dayjsFactory(datetime, 'YYYY-MM-DD HH:mm:ss', true);
  }
  
  /* 'YYYY-MM-DD' 포맷의 문자열을 파싱해서 Dayjs 클래스 인스턴스를 생성합니다.
  * ex)
  * dayjs.fromYMD('2022-02-05');                // 2022-02-05T00:00:00+09:00
  */
  dayjsFactory.fromYMD = function(date: string): dayjs.Dayjs {
    return dayjsFactory(date, 'YYYY-MM-DD', true);
  } 
}

그리고 dayjs.extend() 메서드를 호출해서 플러그인을 적용시켰다.

// main.ts

import * as dayjs from 'dayjs';
import myDayjsPlugin from './myDayjsPlugin';

dayjs.extend(myDayjsPlugin);

그러나 에러 발생ㅜㅜ

Dayjs 공식 문서에 나와있는 그대로 한건데... 플러그인으로 추가한 메서드를 호출하면 아래와 같이 컴파일 에러가 발생했다.

그리고 코드 인텔리젼스에도 플러그인으로 추가한 메서드들이 나타나지 않았다.

무엇이 문제인지 찾아보다 선언 병합을 해줘야 한다는걸 알게 되었다.

선언 병합하기(Declaration Merging)

타입스크립트는 자바스크립트의 수퍼셋(superset) 언어이기 때문에 타입스크립트에서도 자바스크립트처럼 동적으로 객체에 프로퍼티를 추가해줄 수 있다.
그런데 동적으로 객체에 프로퍼티를 추가해주더라도 객체의 타입 정보가 동적으로 바뀌는건 아닌거 같다.
컴파일러가 동적으로 추가된 객체의 프로퍼티 정보를 모르는걸 보면 말이다.(이래서 정적 타입 언어라고 하는건가...?)
객체의 타입이나 객체의 타입의 선언 정보를 수정해야 하는거 같다.
선언 병합을 사용하면 기존 선언을 직접 수정하지 않고도 선언 정보를 변경할 수 있다.
아래는 선언 병합을 사용해서 dayjs 모듈의 선언 정보를 변경해준 것이다.

// myDayjsPlugin.ts

import * as dayjs from 'dayjs';

declare module 'dayjs' {
  interface Dayjs {
    toYMDHMS(): string;
    toYMD(): string;
  }
  export function fromYMDHMS(datetime: string): dayjs.Dayjs;
  export function fromYMD(date: string): dayjs.Dayjs;
}

export default (option, dayjsClass, dayjsFactory) => {
  ...이하 이전과 동일...
}

완성!

선언 병합 이후 컴파일 에러가 더이상 발생하지 않는다.

그리고 코드 인텔리젼스에도 플러그인으로 추가한 메서드들이 잘 표시되는 걸 볼 수 있다.

좋은 웹페이지 즐겨찾기