외부 라이브러리 interface 확장하기

이수빈·2024년 11월 14일
0

Typescript

목록 보기
13/17
post-thumbnail
  • 개발을 하면서 기존에 있던 라이브러리의 인터페이스를 override할 일이 존재한다.

  • 커스텀 설정으로 인터페이스를 오버라이딩 하고 싶을 때 어떻게 해야 하는지 알아보자.

interface의 선언병합

interface의 확장

  • 외부 라이브러리는 보통 확장가능하도록 interface 형태로 작성한다.

  • type과 달리 interface는 선언병합의 특성이 있기 때문에 사용하는 입장에서 확장하기 더 수월하기 때문이다

  • 기본형태는 다음과 같다.

interface Person {
  name: string;
}

interface Person {
  age: number;
}

const person: Person = {
  name: "Alice",
  age: 30,
};

interface가 확장될 때 함수형태가 있다면?

  • 만약 interface에 메소드가 정의되어 있다면?

  • Typescript는 오버로드 된 함수를 생성해 병합한다. => 아래의 class에서는 log가 2가지 형태의 함수를 모두 만족할 수 있는 것이다.

interface Logger {
  log(message: string): void;
}

interface Logger {
  log(message: string, level: number): void;
}

class ConsoleLogger implements Logger {
  log(message: string, level?: number): void {
    if (level !== undefined) {
      console.log(`Level ${level}: ${message}`);
    } else {
      console.log(message);
    }
  }
}

네임스페이스와 병합

  • 인터페이스는 동일한 이름에 네임스페이스와 병합되는 특징이 있다.

  • 아래와 같은 Album 인터페이스는 동일한 이름의 Album namespace와 병합된다

  • 병합되었기 때문에 create기능을 함께 사용 할 수 있다.

interface Album {
  title: string;
}

namespace Album {
  export function create(title: string): Album {
    return { title };
  }
}

const myAlbum = Album.create("Greatest Hits");
console.log(myAlbum.title); // Output: Greatest Hits

Class vs interface Type으로서의 차이

  • 클래스는 생성자를 포함할 수 있으며, 내부에 실제 구현된 메서드와 속성을 가질 수 있습니다. 즉, 클래스 인스턴스를 생성하여 사용할 수 있다.

  • interface는 실제로 구현하지 않는다. => Class가 interface의 구현체라고 생각하면 된다.

  • interface는 다중상속이 가능하다.

  • 클래스를 타입으로 사용하면, 해당 클래스의 구조가 인터페이스처럼 사용할 수 있다.

  • 하지만, 클래스 자체는 구현을 포함하므로 인스턴스를 생성할 수 있는 반면, 인터페이스는 단순히 타입을 정의하는 데만 사용됩니다.

  • 비슷하게 보일 수 있으나, 결국 클래스는 특정 행동과 상태를 정의하는 반면, 인터페이스는 구조를 정의하는 데 중점을 둡니다.

  • 결론적으로는 Class또한 type으로 사용될때는 interface로 동일한 이름은 선언병합이 된다는 것이다.

외부라이브러리 interface 확장방법

node_moudles/@types

  • TypeScript에서 node_modules/@types 디렉토리는 TypeScript 지원이 내장되지 않은 JavaScript 라이브러리에 대한 유형 정의를 제공하여 필수적인 역할을 한다.

  • JS라이브러리 중 TS를 따로 지원해주지 않은 라이브러리는 @types 패키지를 따로 설치해줘야 TS 환경에서 사용 가능하다. @types 만약 이를 지원하지 않는다면, 다른 방법을 찾아야 한다.

  • @types 에 정의된 프로젝트는 TS에서 자동으로 프로젝트에 포함한다.

npm install --save-dev @types/node

그렇다면 추가적으로 커스텀한 모듈 패키지를 포함시키려면?

  • @types에 있는 모듈이 아니기 때문에, tsconfig.json에 따로 커스텀한 모듈 패키지를 사용한다고 명시해 주는 과정이 필요하다.

  • 먼저 확장하고자 하는 외부라이브러리 인터페이스에 대한 동일한 이름의 모듈을 정의한다.

  • 그 다음, global.d.ts 파일로 이를 만들고, TS 컴파일러에게 해당 모듈도 우리 application에서 사용 할 것이라고 명시 해줘야 한다.

  • 기존에 프로젝트에서 type 파일을 생성했다면 굳이 추가 해 줄 필요가 없다. include 옵션에 d.ts옵션이 포함되어 있기 때문이다.

  • 대부분이 잘못 알고 있는 것 중 하나가 프로젝트 내에서 type 파일을 만들게 되면 typeRoots에 추가해야 한다고 알고 있는데 include에 포함돼 있는 .d.ts 파일은 자동으로 typescript가 인식하므로 넣어줄 필요가 없다.

  • include 외에 있는 경우만 추가해주면 된다.

  • 아래 두가지 옵션을 통해 외부 모듈의 존재를 TS 컴파일러에게 알려 줄 수 있다.

typeRoots 옵션 사용

https://www.typescriptlang.org/tsconfig/#typeRoots

  • typeRoots를 통해서 지정한 type 경로는 커스텀 타입이 아니라 일반적으로 외부 라이브러리가 제공하는 모듈의 타입을 정의하기 위해서 사용한다.(즉 우리가 하려는 라이브러리 공통 커스텀이다)

  • tsconfig.json의 typeRoots 옵션은 TypeScript가 유형 정의를 찾아야 하는 하나 이상의 디렉터리를 지정하는 데 사용된다.

  • 기본적으로 TypeScript는 가장 널리 사용되는 JavaScript 라이브러리에 대한 유형 정의가 설치된 node_modules/@types 디렉토리에서 type을 검색한다.

  • tsconfig.json에서 typeRoots 옵션을 설정하면 TypeScript는 typeRoots에 명시된 경로만 검색하여 type을 찾는다.

  • typeRoots에 대한 사용자 정의 디렉터리를 제공하는 경우 명시적으로 포함하지 않는 한 TypeScript는 더 이상 node_modules/@types를 자동으로 포함하지 않는다.

{
  "compilerOptions": {
    "typeRoots": ["./custom-types", "./node_modules/@types"]
  }}

types옵션 사용

https://www.typescriptlang.org/tsconfig/#types

  • types 옵션을 사용하면 이름으로 유형 정의 배열을 지정할 수 있다.

  • 이를 사용하면 TypeScript는 지정된 유형 정의만 포함하고 명시적으로 포함되지 않는 한 node_modules/@types 디렉토리의 다른 유형 정의를 무시한다. 즉 node_modules/@types에서 타입 범위를 제한시킨다.

{
  "compilerOptions": {
    "types": ["node", "jest"]
  }}
  • 이 경우 TypeScript는 node_modules/@types에서 사용 가능한 다른 모든 유형을 무시하고 node 및 jest에 대한 유형만 포한다.

types with typeRoots

  • types 옵션은 typeRoots 옵션과 함께 사용 할 수도 있다.
{
  "compilerOptions": {
    "typeRoots": ["./custom-types", "./node_modules/@types"],
    "types": ["my-library"]
  }}
  • 이런식으로 컴파일러 옵션을 설정하면, TypeScript는 typeRoots경로에서 먼저 ./custom-types/my-library 및 node_modules/@types/my-library에서 type에 명시된 my-library 패키지를 찾는다.
  • my-library 폴더에는 index.d.ts 또는 기타 TypeScript 선언 파일이 포함되어 있어야 올바르게 인식된다.

interface 확장시 의문점들

1.인터페이스 선언시 인터페이스 안에 인터페이스가 있는 구조일때, 선언병합시 어떤걸 바라볼까?

=> 모든 인터페이스가 선언병합된 이후 컴파일 됨 => 즉 모두 flat 한 형태의 인터페이스가 된다고 생각하면 됨.

  1. 만약 외부 라이브러리가 Class로 작성되었는데, 동일한 이름의 인터페이스로도 확장이 가능한가?

=> 된다. Class자체도 type으로 사용 될 때는 interface로 트랜스파일된다.

ref)
https://velog.io/@sooran/tsconfig.json-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%95%8C%EA%B3%A0-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0#%EB%8B%A8%EC%88%9C-%ED%83%80%EC%9E%85-%EC%B2%B4%ED%81%AC%EC%9A%A9%EC%9C%BC%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%A0%A4%EB%A9%B4

profile
응애 나 애기 개발자

0개의 댓글