[타입스크립트] 타입 정의가 없는 경우 타입 정의하기

천둥상어

·

2024. 9. 21. 22:19

반응형

타입스크립트를 적용하면 몇가지 문제를 맞닥뜨리게 된다.
그 중 빈번하게 발생하는 이슈는 타입 정의다.
 
보통 사용하는 라이브러리나 플러그인이 공식적으로
타입 스크립트를 지원하지 않는 경우이다.
 
npm 저장소에 공개적으로 타입 정의 파일이 있다면
해당 모듈을 설치하면 된다.
 
하지만 그렇지 않다면 번거롭지만
개발자가 직접 타입 정의를 해주면 된다.
 


타입 정의 파일 생성 (.d.ts 파일 만들기)

Test.js 파일이 있고 해당 파일을 import 하여 메서드에 접근한다면
당연히 타입 정의가 되어 있지 않아서 타입 추론이 안된다.
 
Main.ts 에서 Test.js import 하여 함수를 호출해보자.
타입스크립트가 적용된다면 import 문에서부터 에러가 발생한다.
 
Main.ts

import * as Test from "./Test";

export class Main {
  constructor() {}
}

new Main();

 
Test.js

export function testFnc_number($n) {
  console.log($n);
}

export function testFnc_string($n) {
  console.log($n);
}

 

.d.ts 만들기

Test.js와 같은 이름으로 Test.d.ts 파일을 같은 위치에 생성한다.
빌드를 한다면 실행은 되고 콘솔창에 33은 찍히지만
타입 추론은 되지 않고 있다.
 
이 상태에서 testFnc_number에 커서를 올려보면 타입이 any로 나온다.
그리고 import 되는 파일이 모듈이 아니라고 경고가 뜬다.

 

.d.ts. 파일에 타입 정의하기

아래와 같이 Test.d.ts 파일에 타입을 정의한다.

export function testFnc_number($n: number): void;

export function testFnc_string($n: string): void;

 
그러면 모든 경고성 에러가 사라지고 타입 추론이 되는 것을 볼수 있다.

 


declare 로 타입 정의하기

cdn 방식으로 JS 라이브러리를 가져오는 경우에는 declare로 타입을 정의하면 된다.
 
index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title></title>
    <script src="MyLib.js"></script>
  </head>
  <body>
    <script type="module" src="src/Main.ts"></script>
  </body>
</html>

 
MyLib.js

(function () {
  this.MyLib = this.MyLib || {};
  MyLib.setAB = function (a, b) {
    console.log(`a: ${a}, b: ${b}`);
  };
 
  if (typeof window !== "undefined") {
    window.MyLib = this.MyLib;
  }
})();

 
Main.ts

declare global {
  interface MyLibType {
    setAB(a: string, b: string): void;
  }
  const MyLib: MyLibType;
}

export class Main {
  constructor() {
    MyLib.setAB("A 출력", "B 출력");
  }
}

new Main();

 

간단히 함수나 변수를 가져오는건 이걸로 충분하지만...

라이브러리의 경우 Class로 포함하고 있을 것이다.

 

그래서 declare를 .d.ts 파일에 선언해서 사용하면 더 효율적이다.


.d.ts. 파일에 declare 선언하기

MyLibRect라는 Class를 추가했다.

Rect 클래스는 width 값을 리턴하는 메서드 getWidth()를 가지고 있다.

MyLib.d.ts를 생성해서 아래와 같이 작성하면

Main.ts에서 타입 추론이 가능하다.

 

MyLib.js

(function () {
  this.MyLib = this.MyLib || {};
  MyLib.setAB = function (a, b) {
    console.log(`a: ${a}, b: ${b}`);
  };

  class Rect {
    constructor($width, $height) {
      this.width = $width;
      this.height = $height;
    }

    getWidth() {
      return this.width;
    }
  }

  MyLib.Rect = Rect;
  if (typeof window !== "undefined") {
    window.MyLib = this.MyLib;
  }
})();

 

MyLib.d.ts

declare namespace MyLib {
  
  function setAB(a: string, b: string): void;

  class Rect {
    constructor(width: number, height: number);
    getWidth(): number;
  }
}

 

Main.ts

export class Main {
  constructor() {
    MyLib.setAB("A 출력", "B 출력");
    const rect = new MyLib.Rect(400, 400);
    const width = rect.getWidth();
    console.log(width);
  }
}
new Main();

타입 추론 문제로 고통을 받다보면 그냥 JS로 쓰고 싶은 경우가 많다.
그렇다고 타입스크립트를 포기하자니 불안하고 기술 스펙이 다운되는 기분이다.
슈퍼셋의 고질적인 문제점이라 계속 안고 가야 할듯...

 

반응형