Disabling Import Elision
TL;DR
コンパイラオプション --preserveValueImports
が導入された。
未使用のインポート
インポートされた変数や型がTypeScriptによって「未使用」と判断される時、トランスパイル後のJavaScriptには出力されない。
この挙動で困るのはevalを使ってランタイムで変数を参照するようなケース。
// foo.ts
export const foo = "FOO";
// bar.ts
import { foo } from "./foo";
console.log(eval("foo")); // <=====
./node_modules/.bin/tsc ./bar.ts
// bar.js(トランスパイルによって出力されたJavaScript)
console.log(eval("foo"));
export {};
eval
は与えられたテキストをJavaScriptのコードとして実行する。foo
の実体はトランスパイラによって削除されているためランタイムエラーが発生する。
ReferenceError: foo is not defined
セキュリティの問題もあり eval
でコードを評価することはほとんどなくなったが、SvelteやVueで似たような問題が起こる。
<!-- A .vue File -->
<script setup>
import { someFunc } from "./some-module.js";
</script>
<button @click="someFunc">Click me!</button>
--preserveValueImports
https://www.typescriptlang.org/ja/tsconfig#preserveValueImports
新しく導入されたオプションで未使用のインポートをコントロールできるようになった。
false(デフォルト)
以前のバージョンと同じ挙動。未使用のインポートが削除される。
./node_modules/.bin/tsc ./bar.ts \
--module es2022 \
--preserveValueImports false
// 出力されたJavaScript
console.log(eval("foo"));
export {};
true
未使用のインポートが出力される。
./node_modules/.bin/tsc ./bar.ts \
--module es2022 \
--preserveValueImports true
// 出力されたJavaScript
import { foo } from "./foo";
console.log(eval("foo"));
--isolatedModules
https://www.typescriptlang.org/ja/tsconfig#isolatedModules
preserveValueImports
を isolatedModules
オプションと同時に指定する場合、型のインポートで注意が必要。
// foo.ts
export type Foo = {};
// bar.ts
import { Foo } from "./foo";
const foo: Foo = {};
上のコードを isolatedModules:true
にして tsc
に渡すとエラーが発生する。
./node_modules/.bin/tsc ./bar.ts \
--module es2022 \
--preserveValueImports true \
--isolatedModules true
error TS1444:
'Foo' is a type and must be imported usng a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.
このエラーは「単一ファイルに出力すると型情報が消えてしまう」ことを警告している。
解決策は「型のみインポートする」シンタックスに書き換えること。
// import { Foo } from "./foo";
import type { Foo } from "./foo";
const foo: Foo = {};
./node_modules/.bin/tsc ./bar.ts \
--module es2022 \
--preserveValueImports true \
--isolatedModules true
# OK
Last updated