본문 바로가기

프론트엔드(Front-End)/TypeScript

[TypeScript] 타입스크립트의 응용(declare, d.ts, module, ambient module, keyof)

타입스크립트의 import, export

바닐라 자바스크립트에서도 자바스크립트 파일로 멋지게 만든 함수나 변수를 외부로 내보내거나,

혹은 다른 사람이 만든 좋은 라이브러리를 가져다 쓸 수 있습니다. import 와 export 덕분이죠.

타입스크립트도 마찬가지로 다른 타입스크립트 파일을 import 하거나 export하여 사용할 수 있습니다.

사실 타입스크립트의 import와, export는 자바스크립트와 동일하기 때문에 아래와 같이 사용하면 됩니다.

 

// MyModule.ts
//타입 스크립트 파일 내보내기

function print(value: any) {
  console.log(value);
}

export { print };

 

// Chapter8.ts

import { print } from "./MyModule";
print("hello world!"); // hello world!

 

타입스크립트와 declare

타입스크립트에서 타입을 미리 선언하여 하나로 관리할 수 있다면 어떨까요?

물론 회사 방침이나 개발자의 성향에 따라 이렇게 정리하여 사용하지 않을 수 도 있겠지만,

타입스크립트는 타입을 별도로 저장한 뒤 다른 타입스크립트 파일에서도 사용할 수 있도록 지원합니다.

 

예를 들어 아래와 같이 타입만을 작성한 파일이 있다고 해봅시다.

 

// DogType.ts

// 하나의 타입을 내보낼 때
declare type DogType = string;

 

이렇게 타입을 내보내게 되면 다른 타입스크립트 파일에서도 이 타입을 아래와 같이 사용할 수 있게 됩니다.

 

// Chapter8.ts

let value: DogType = "dog"; // 선언한적 없지만 사용 가능!

 

타입스크립트와 ambient module

사실 타입스크립트에는 한가지 비밀이 있습니다.

타입 스크립트는 그냥 변수나 함수 등을 선언해두면 ambient module이 되어 다른 타입스크립트 파일에서도 사용 가능합니다.

지난 포스트에서 사용한 classifier라는 메서드를 Chapter8.ts에서 사용해보도록 하겠습니다.

 

import { print } from "./MyModule";
print("hello world!"); // hello world!

let value: DogType = "dog"; // 선언한적 없지만 사용 가능!

classifier("hello world!");

 

분명 export 문법이나 별다른 속성을 건든 적이 없는데 자연스럽게 사용이 가능합니다.

그래서 타입스크립트를 locally하게 사용하고 싶다면, 아래와 같이 타입스크립트 파일 최상단에 export{} 구문을 적어주면 됩니다. 위의 예제 코드 중 DogType.ts에 export{} 구문을 추가해보도록 하겠습니다.

export {};

// 하나의 타입을 내보낼 때
declare type DogType = string;

 

분명 잘 지정됐었던 타입인데, Chapter8.ts로 가보니 컴파일 오류가 발생한 것을 확인할 수 있습니다.

 

 

나는 DogType.ts의 변수 등을 locally하게 사용하고, 동시에 DogType은 외부로 내보내고 싶다면 어떻게 해야할까요?

바로 아래와 같이 declare global 키워드를 통해 locally 하게 만든 파일 임에도 global type을 내보낼 수 있습니다.

 

export {};

declare global {
  type DogType = string;
}

 

 

이제는 컴파일 오류가 발생하지 않는 것을 확인할 수 있네요.

 

타입스크립트와 d.ts

위와 같이 타입스크립트에서는 타입만 별도 파일로 분리하여 관리할 수도 있는데요.

이처럼 타입만을 별도로 관리하는 파일이 d.ts 파일입니다.

d.ts 파일은 아래와 같이 타입만을 담을 수 있으며 함수는 파라미터나 리턴 타입 등만 가능합니다.

 

export type Count = number;
export type Sum = (x :number ,y :number) => number
export interface Product { name : string }

 

만약 모든 타입 스크립트에 대하여 자동으로 d.ts 파일을 만들고 싶다면

아래와 같이 tsconfig.json 파일에 속성을 추가하면 됩니다.

 

// tsconfig.json

{
    "compilerOptions": {
        "target": "es5",
        "module": "es6",
        "declaration": true, // 이 속성 추가
    }
}

 

타입스크립트와 keyof

타입스크립트에서는 어떤 오브젝트의 프로퍼티들의 타입을 모두 추출할 수도 있습니다.

각각의 타입을 추출하는 것은 아니고, 오브젝트의 프로퍼티들의 모든 타입을 묶은 하나의 유니온 타입을 얻을 수 있습니다.

아래와 같이 인터페이스가 하나 있다고 해보겠습니다.

 

interface Person {
    age:number,
    name:string
}

type newPerson = keyof Person; // Union type return
let value1:newPerson = 'name'; // string or number OK!

 

여기서 프로퍼티들의 속성을 추출하여 위와 같이 유니온 타입으로 사용할 수 있습니다.

 

오브젝트의 프로퍼티를 가변적으로 선언하기

타입스크립트에서 함수의 rest parameter가 있듯이 오브젝트의 프로퍼티도 가변적으로 설정할 수 있을까요?

자바스크립트의 오브젝트는 key-value 쌍으로 이루어져 있다는 특징이 있는데요.

그래서 아래와 같이 가변적으로 프로퍼티에 대한 타입을 선언할 수 있습니다.

 

interface Person2 {
  [key: string]: number;
}

let newPerson1: Person2 = { weight: 123, age: 123 };
let newPerson2: Person2 = { weight: 123, age: 123, height: 456 };

 

Assertion을 활용한 타입 변환기 만들기

앞서 배운 타입스크립트의 두가지 문법을 잘 활용하면,

타입을 변환하는 타입 체인저 타입을 만들수도 있는데요. 용법은 아래와 같습니다.

 

type Car = {
    color : boolean,
    model : boolean,
    price : boolean | number
}

type TypeChanger<MyType> = {
    [key in keyof MyType]:string // mapping
}

type newType = TypeChanger<Car>;

 

 

분명 Car 오브젝트 타입의 프로퍼티 속성은 제각각이었는데,

이제는 하나의 속성으로 통일된 타입을 만드는데 성공했네요. 

 

이어서 제네렉을 활용하여 타입 체인저를 만들 수도 있습니다.

 

// 엉망으로 만든 타입!
type Bus = {
    color:string,
    model :boolean,
    price: number,
}

type TypeChanger2<T> = {
    [key in keyof T]: string|number
}

type newBus = TypeChanger2<Bus>

let myBus:newBus = {color:'red', model:'hyundai', price:123};
console.log(myBus);

 

 

이번데도 타입이 잘 변환된 것을 확인할 수 있네요.