
import type
export type
원래의 import, export 문법과 동일하나 뒤에 type만 덧붙여주면 된다.
import type { SomeThing } from "./some-module.js";
export type { SomeThing };
🚨 import type으로 받아온 class는 확장이 불가능하다.
// 클래스가 선언된 파일
export class sampleTypes {
first!: string;
second!: number;
third!: boolean;
}
export class sampleTypes2 {
first!: string;
second!: number;
third!: boolean;
}
// 클래스가 import 되어 확장된 파일
import { sampleTypes } from "types/new";
import type { sampleTypes2 } from "types/new";
class newTypes extends sampleTypes {
hi!: string;
hello!: number;
}
class newTypes2 extends sampleTypes2 {
hi!: string;
hello!: number;
}
// 에러 발생!
// 'sampleTypes2'은(는) 'import type'을 사용하여 가져왔으므로 값으로 사용할 수 없습니다.
🚨 기본 import와 default import는 한 번에 할 수 없다!
export class sampleTypes {
first!: string;
second!: number;
third!: boolean;
}
export default class sampleTypes2 {
first!: string;
second!: number;
third!: boolean;
}
// 에러 발생!
// 형식 전용 가져오기는 기본 가져오기 또는 명명된 바인딩을 지정할 수 있지만,
// 둘 다 지정할 수는 없습니다.
import type sampleTypes2, { sampleTypes } from "types/new";
// TS 코드
import sampleTypes from 'types/new'
let newType: sameTypes = // ~
// 변환 후 JS 코드
// type import 부분은 다른 부수효과를 발생 시키지 않을 것으로 예상되어 삭제됨
let newType = // ~
TS 코드가 컴파일 될 때, 인터페이스와 타입은 사라져서 방출된 결과물에 존재하지 않는다.
만약 import가 이를 위해서만 이루어졌다고 파악될 경우 JS로 변환된 파일에는 해당 import 선언문도 들어가지 않는다.
// 타입이 선언된 파일
export type sampleTypes = {
first: string;
second: number;
third: boolean;
};
export const showTypes = (config: sampleTypes) => {
console.log(config);
};
// 타입을 호출하는 파일
import { sampleTypes, showTypes } from "types/new";
transpileModule API, Babel을 통해 프로젝트의 모듈을 하나씩 컴파일하려 할 때 생기는 문제가 있다.// import 된 후 export 되는 경우 이것은 단순 타입이 맞을까? 아니면 값으로 취급되어야 할까?
import { reExportedType } from "./foo.js";
export { reExportedType };
정답은 이 파일에 국한된 경우 알 수 있는 방법이 없다는 것이다.
TS 컴파일러는 실시간으로 타입 정보를 생략하려 하지만 re-export 된 타입이 해당 파일에서만 사용된다면 이것을 인지하지 못해 문제가 발생한다.
이러한 이유로 TS의 transpileModule API, Babel은 reExportedType이 단순히 타입으로만 사용된 경우에도 제대로 동작하지 못하게 된다.
이는 타입 체크 과정의 안정성을 저해하고, 실제 빌드 이후 결과물의 용량을 불필요하게 늘릴 수 있다.
// 오직 타입만 선언하였으므로 import elision에 의해 삭제된다.
import { SomeTypeFoo, SomeOtherTypeBar } from "./module-with-side-effects";
// 따라서 이 선언문이 반드시 함께 사용되어야 한다.
import "./module-with-side-effects";
두 번째 선언문이 존재하지 않을 경우,
webpack은 변환된 JS코드를 실행할 때에 존재하지 않는 것에 대한 import의 결과로 에러를 발생시킨다.
만약 부수효과를 포함하고 있는 모듈에서 타입을 import 했다면 이 import 구절은 삭제되어 부수효과도 실행되지 않는 문제가 생긴다.
import 선언문이 명시적으로 type-only로 지정되어 있지 않을 경우 방출 시 컴파일러가 import 선언 삭제를 멈추도록 하였다.
이를 통해 부수 효과를 위해 imports를 보존하고 싶었던 사용자들이 필요한 import 선언문만 보존할 수 있었다.
또한 단일 파일 단위로 코드를 변환할 때에 re-export가 타입 정보만을 내보내는 경우 해당 구문을 삭제하도록 식별자를 명시할 수 있는 기능을 제공하였다.
export { T } from './mod'를 사용하여 타입 T를 re-export 할 수 있었다.하지만 --isolatedModules 플래그의 도입으로 이 방식은 사용되지 않기 시작했다.
isolatedModules
isolatedModules 플래그를 도입하면 타입의 re-exporting 자체를 에러로 처리하므로 단일 파일 변환 시 모듈 간 의존성을 엄격하게 제한할 수 있게 되었다.단순히
isolatedModules만 사용할 경우의 문제점
isolatedModules만을 사용하면서 re-exporting을 하려면 아래와 같은 방식을 사용해야 했다.import { sampleType } from "./a";
export type sampleType = sampleType;이 방식을 통해 모듈에서 타입 정보만을 가져오므로 불필요한 값이 메모리에 로딩되는 문제를 해결하였다.
import type을 사용할 경우 이러한 import는 항상 컴파일 과정에서 완전히 제거되어 런타임에는 남아있지 않게 된다.
export type 또한 타입의 맥락에서만 사용되는 export 구문이므로, 변환 과정에서 삭제된다.
명시적으로 타입만을 가져온다고 보장되므로 JS 변환 시 삭제된다.
Babel 등의 도구가 isolatedModules 옵션을 통해 코드를 추정하기 더 용이해진다.
import type을 통해 명시적으로 작성할 수 있으므로 작동하는 플래그이다.remove
preserve
error