TypeScript/tsconfig.jsonのtarget, moduleなどをどう設定すべきか
TypeScriptでトップレベルawaitを使おうとしたら、エラーが出た
トップレベルの 'await' 式は、'module' オプションが 'es2022'、'esnext'、'system'、'node16' または 'nodenext' に設定されていて、'target' オプションが 'es2017' 以上に設定されている場合にのみ使用できます。ts(1378)
エラーが出たときの環境
$ tsc --version
Version 5.3.3
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
// ...
}
}
{
"main": "index.js",
"license": "MIT",
// typeは未記載
// ...
}
tsconfig.json
に"module": "ESNext"
を、package.json
に"type": "module"
を指定することでESModuleとして動作させることにした
import
で拡張子まで含めたファイルパスを指定する必要があった
// Cannot find module './routes'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option?ts(2792)
import router from "./routes";
// 内部的にはJavaScriptなので、拡張子は".js"
import router from "./routes/index.js";
ライブラリのインポートでエラーになった
Cannot find module '@vendia/serverless-express'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option?ts(2792)
import serverlessExpress from "@vendia/serverless-express";
エラーメッセージの通り、tsconfig.json
に"moduleResolution": "NodeNext"
を追記したら、今度はmodule
がダメと言われたので"module": "NodeNext",
に修正
{
"compilerOptions": {
"target": "es6",
// Option 'module' must be set to 'NodeNext' when option 'moduleResolution' is set to 'NodeNext'.ts
"module": "ESNext",
↓
"module": "NodeNext",
"moduleResolution": "NodeNext"
まだ、トップレベルawaitのエラー消えないと思ったら、tsconfig.json
のtarget
の修正が漏れてた
{
"compilerOptions": {
// (前略)'target' オプションが 'es2017' 以上に設定されている場合にのみ使用できます。ts(1378)
"target": "es6",
↓
"target": "es2022",
別の箇所でエラーが出る
import serverlessExpress from "@vendia/serverless-express";
// この式は呼び出し可能ではありません。
// 型 'typeof import("/.../node_modules/@vendia/serverless-express/src/index")' には呼び出しシグネチャがありません。ts(2349)
export const handler = serverlessExpress({ app });
関係ないかもだけど、@vendia/serverless-express
は@codegenie/serverless-express
に移管していた
移管したけど解決せず
どうも呼び出し方が間違っていたっぽい?
// 型定義
import configure from "./configure"
export default configure;
export { default as configure } from "./configure"
export { getCurrentInvoke } from "./current-invoke"
// 上でdefaultとしてexportされていたconfigureの定義
// (前略)
interface ConfigureParams {
app: RequestListener; // <========= もともと渡していたのはこれ?
logSettings?: LogSettings;
log?: Logger;
framework?: Framework;
binaryMimeTypes?: string[];
binarySettings?: BinarySettings;
resolutionMode?: string;
eventSourceName?: string;
eventSource?: EventSource; // TODO:
eventSourceRoutes?: { [key in EventSources]?: string };
respondWithErrors?: boolean;
}
interface BinarySettings {
isBinary?: Function | boolean;
contentTypes?: string[];
}
export interface ConfigureResult<TEvent = any, TResult = any> {
handler: Handler<TEvent, TResult>;
log: Logger;
proxy: (proxyParams: ProxyParams) => Promise<Object>;
}
declare function configure<TEvent = any, TResult = any>(configureParams: ConfigureParams): Handler<TEvent, TResult> & ConfigureResult<TEvent, TResult>;
// declare function proxy(proxyParams: ProxyParams): Promise<any>
export default configure;
明示的にconfigure
を呼び出すようにしたら、エラーは消えた
export const handler = serverlessExpress.configure({ app });
import
で拡張子まで書かなくても良くするには、tsconfig.json
に"moduleResolution": "Bundler"
をしていすればよいらしい。
ただ、module
には`ES2015以降を指定する必要がある
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
// Option 'bundler' can only be used when 'module' is set to 'es2015' or later.ts
"moduleResolution": "Bundler"
module
にES2022
を指定したら、修正したserverlessExpress
の呼び出しで怒られた
元の呼び出し方に戻した
// プロパティ 'configure' は型 '<TEvent = any, TResult = any>(configureParams: ConfigureParams) => Handler<TEvent, TResult> & ConfigureResult<TEvent, TResult>' に存在しません。ts(2339)
export const handler = serverlessExpress.configure({ app });
// ↓
export const handler = serverlessExpress({ app });
"moduleResolution": "Bundler"
はtsc
以外ツールでビルドする場合に利用するものらしい
今回はtsc
を使っているため、"moduleResolution": "Node16"
に戻した
実行したらエラーが出た
[0] TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /home/ak2ie/kintone_line_case_management/src/index.ts
[0] at new NodeError (node:internal/errors:405:5)
[0] at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:99:9)
[0] at defaultGetFormat (node:internal/modules/esm/get_format:142:36)
[0] at defaultLoad (node:internal/modules/esm/load:91:20)
[0] at DefaultModuleLoader.load (node:internal/modules/esm/loader:263:26)
[0] at DefaultModuleLoader.moduleProvider (node:internal/modules/esm/loader:179:22)
[0] at new ModuleJob (node:internal/modules/esm/module_job:63:26)
[0] at DefaultModuleLoader.#createModuleJob (node:internal/modules/esm/loader:203:17)
[0] at DefaultModuleLoader.getJobFromResolveResult (node:internal/modules/esm/loader:156:34)
[0] at DefaultModuleLoader.getModuleJob (node:internal/modules/esm/loader:141:17) {
[0] code: 'ERR_UNKNOWN_FILE_EXTENSION'
[0] }
ts-node
で実行してたけど、オプション追加が必要らしい
ts-node --esm src/index.ts
ts-node --esm
でもエラーが出る
ts-node+nodemon
を使ってきたけど、そもそもこれがダメ?
tsx
を使うとうまくいった
$ yarn add tsx --dev
{
"scripts": {
"dev": "tsx watch src/index.ts",