tsconfig.json [Interop Constraints]

0

tsconfig.json

목록 보기
7/8
post-thumbnail

최종 수정일 : 2021년 9월 8일

!주의 이 문서는 유익하지 않습니다(?).

목차

allowSyntheticDefaultImports
esModuleInterop
forceConsistentCasingInFileNames
isolatedModules
preserveSymlinks

Options

allowSyntheticDefaultImports

원본 보기

true로 하면, allowSyntheticDefaultImports는 이렇게 import 하는 것을 허용합니다:

import React from "react";

대신:

import * as React from "react";

모듈이 default export명시하지 않은 경우.

예를 들어, allowSyntheticDefaultImports를 사용하지 않을 때:

// @filename: utilFunctions.js

>> Module '"/home/runner/work/TypeScript-Website/TypeScript-Website/utilFunctions"' has no default export.

const getStringLength = (str) => str.length;
 
module.exports = {
  getStringLength,
};
 
// @filename: index.ts
import utils from "./utilFunctions";
 
const count = utils.getStringLength("Check JS");

이 코드는 import 할 수 있는 default 객체가 없기 때문에 에러를 일으킵니다. 그럼에도 불구하고, 할 수 있을 것 처럼 느껴집니다. 편의를 위해, 바벨같은 트랜스파일러는 default가 없다면 자동적으로 default를 생성합니다. 모듈을 좀 더 비슷하게 만들기:

// @filename: utilFunctions.js
const getStringLength = (str) => str.length;
const allFunctions = {
  getStringLength,
};
module.exports = allFunctions;
module.exports.default = allFunctions;

이 플래그는 TypeScript가 JavaScript를 내보내는데 영향을 주지 않고, 오직 타입 확인에만 영향을 줍니다. extra code에서 바벨과 함께 TypeScript가 좀 더 인체공학적으로 사용하도록 모듈의 default export를 만들어서 내보내도록 합니다.

esModuleInterop

원본 보기

기본적으로(esModuleInterop가 false이거나 설정되지 않음) TypeScript는 CommonJS/AMD/UMD 모듈을 ES6 모듈과 비슷하게 취급합니다. 이를 통해, 잘못된 가정임이 밝혀진 두 파트가 있습니다:

  • namespace는 import * as moment from "moment" 처럼 import 하면 const moment = require("moment") 와 동일하게 동작한다.
  • import moment from "moment" 처럼 기본적인 import는 const moment = require("moment").default 와 동일하게 동작한다.

이 불일치는 두 가지 이슈를 유발합니다:

  • ES6 모듈 스펙 사양에서 namespace import(import * as x)는 오직 object만 가능하고, TypeScript는 import를 = require("x")와 동일하게 취급하여 호출 가능한 함수처럼 취급합니다. 이것은 스펙의 권장 사항을 위반합니다.
  • ES6 모듈 스펙에선 맞지만, CommonJS/AMD/UMD 모듈을 사용하는 많은 라이브러리들이 TypeScript의 구현만큼 암격하게 준수하진 않았습니다.

esModuleInterop을 활성화하면 TypeScript가 코드를 트랜스파일하며 문제를 해결합니다. 첫번 째는 컴파일러의 동작을 변경하고, 두번 째는 내보낸 JavaScript의 호환성의 보장을 제공하는 두 가지 헬퍼 함수에 의해 해결됩니다:

import * as fs from "fs";
import _ from "lodash";

fs.readFileSync("file.txt", "utf8");
_.chunk(["a", "b", "c", "d"], 2);

esModuleInterop를 비활성화 했을 때:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const lodash_1 = require("lodash");
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);
 

esModuleInteroptrue로 활성화 했을 때:

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const lodash_1 = __importDefault(require("lodash"));
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);

주의: namespace import import * as fs from "fs"는 import된 object가 보유한 속성들만을 위해 등록합니다(기본적으로 prototype 체인이 아닌 object에 등록된 속성). 상속된 속성을 사용하는 API가 정의된 모듈을 import 하는 중이고, 기본 import 형태(import fs from "fs") 사용을 필요로 하거나, 또는 esModuleInterop을 비활성화하는 경우.

주의: importHelpers를 활성화하여 간결한 JS를 내보낼 수 있습니다:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fs = (0, tslib_1.__importStar)(require("fs"));
const lodash_1 = (0, tslib_1.__importDefault)(require("lodash"));
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);
 

esModuleInterop를 활성화하면 allowSyntheticDefaultImports도 활성화 됩니다.

forceConsistentCasingInFileNames

원본 보기

TypeScript는 실행 중인 파일 시스템의 대/소문자 구분 규칙을 따릅니다. 일부 개발자는 대/소문자를 구분하는 파일 시스템에서 작업하고 다른 개발자는 그렇지 않은 경우 이 문제가 발생할 수 있습니다. 파일이 ./FileManager.tsfileManager.ts라고 import 할 경우 파일은 대/소문자를 구분하지 않는 파일 시스템에서 찾을 수 있지만 대/소문자를 구분하는 파일 시스템에서는 찾을 수 없습니다.

이 옵션을 사용하면, 프로그램이 디스크에 있는 파일과 다른 대/소문자로 포함하려 하면 TypeScript는 에러를 일으킬 것입니다.

isolatedModules

원본 보기

TypeScript를 이용하여 TypeScript 로 부터 JavaScript 코드를 만들 수 있지만, Babel 같은 다른 트랜스파일러도 일반적으로 사용합니다.
하지만, 다른 트랜스파일러는 한 번에 하나의 파일에서만 작동하므로 전체 시스템을 이해해야 하는 코드 변환을 적용할 수 없습니다.
이 제한은 일부 빌드 도구에서 사용하는 TypeScript의 ts.transpileModule API 에도 적용됩니다.

이러한 제한으로 인해 const enumnamespace와 같은 일부 TypeScript 기능에 런타임 문제가 발생할 수 있습니다. isolatedModules 플래그를 설정하면 단일 파일 변환 프로세스에서 제대로 해석할 수 없는 코드를 작성할 경우 TypeScript에 경고를 표시합니다.

코드 동작이나 TypeScript의 검사 및 내보내기 프로세스의 동작은 변경되지 않습니다.

isolatedModules를 활성화 할 때 작동하지 않는 코드의 몇 가지 예시입니다.

값이 없는 식별자의 export

TypeScript에서는, 타입을 import 할 수 있고 그 후에 export 할 수도 있습니다:

import { someType, someFunction } from "someModule";
 
someFunction();
 
export { someType, someFunction };

왜냐하면 거기엔 someType을 위한 값이 없기 때문에, export는 export를 시도하지 않습니다 (아마도 JavaScript에서 런타임 오류일 것입니다):

export { someFunction };

단일 파일 트랜스파일러는 someType이 값을 생성했는지 아닌지 여부를 알 수 없기 때문에, 타입만 참조하는 이름을 export 것은 에러입니다.

모듈이 아닌 파일

isolatedModules이 비활성화일 때, 구현된 모든 파일은 반드시 모듈이어야 합니다 (import/export 형태여야 한다는 뜻). 파일이 모듈이 아닐 경우 에러가 발생합니다:

function fn() {}
>> 'index.ts' cannot be compiled under '--isolatedModules' because it is considered a global script file. Add an import, export, or an empty 'export {}' statement to make it a module.

.d.ts 파일은 이 제한이 적용되지 않습니다.

const enum 멤버에 대한 참조

TypeScript는 const enum 멤버의 참조는 제거하고 실제 값을 JavaScript로 내보냅니다.
이레 TypeScript는:

declare const enum Numbers {
  Zero = 0,
  One = 1,
}
console.log(Numbers.Zero + Numbers.One);

아래 JavaScript로 변환됩니다:

"use strict";
console.log(0 + 1);
 

이 멤버들의 값들 모른다면 다른 트랜스파일러들은 Numbers의 참조를 대체할 수 없습니다.
그대로 두면 런타임 에러가 발생됩니다(런타임에 Numbers 객체가 없어서).
왜냐하면, isolatedModules이 사용될 때 const enum 멤버를 참조하면에러가 발생합니다.

원본 보기

이것은 Node.js에서 동일한 플래그를 반영합니다; symlink의 실제 경로를 확인하지 않습니다.

이 플래그는 또한 Webpack의 resolve.symlinks 옵션의 반대 행동을 보입니다(TypeScript의 preserveSymlinkstrue로 두고 Webpack의 resolve.symlinksfalse로 하거나, 반대의 경우도. 다시 말해, 우리는 이 문제를 해결할 수 있는 것이 아닙니다.).

이것을 활성화하면, 모듈과 패키지의 참조는(예: import/// <reference type="..." />를 지시하는) 심볼릭 링크가 확인되는 경로보다는, 심볼릭 링크 파일의 위치를 모두 확인합니다.

profile
지상 최강의 개발자 쥬니니

0개의 댓글