Ответ на данный вопрос находится в этом issue:
https://github.com/TypeStrong/ts-node/discussions/1450
Для того, чтобы алиасы работали нужно загружать файлы через custom loader:
// this not work in Node 19
import { resolve as resolveTs } from 'ts-node/esm';
import * as tsConfigPaths from 'tsconfig-paths';
import { pathToFileURL } from 'url';
const { absoluteBaseUrl, paths } = tsConfigPaths.loadConfig();
const matchPath = tsConfigPaths.createMatchPath(absoluteBaseUrl, paths);
export function resolve(specifier, ctx, defaultResolve) {
const lastIndexOfIndex = specifier.lastIndexOf('/index.js');
if (lastIndexOfIndex !== -1) {
// Handle index.js
const trimmed = specifier.substring(0, lastIndexOfIndex);
const match = matchPath(trimmed);
if (match) return resolveTs(pathToFileURL(`${match}/index.js`).href, ctx, defaultResolve);
} else if (specifier.endsWith('.js')) {
// Handle *.js
const trimmed = specifier.substring(0, specifier.length - 3);
const match = matchPath(trimmed);
if (match) return resolveTs(pathToFileURL(`${match}.js`).href, ctx, defaultResolve);
}
return resolveTs(specifier, ctx, defaultResolve);
}
export { load, transformSource } from 'ts-node/esm';
Запускать ts-node надо командой:
node --loader ./src/loader.js src/main"
файл tsconfig.json
{
"compilerOptions": {
"module": "Node16",
"target": "ESNext",
"outDir": "./build",
"baseUrl": "./src",
"paths": {
"@helpers/*": ["helpers/sub1/*"]
}
},
"include": ["src/**/*"],
"exclude": [
"node_modules",
],
"ts-node": {
"esm": true,
"experimentalSpecifierResolution": "node",
"transpileOnly": true,
"files": true,
"require": ["tsconfig-paths/register"]
}
}
Работающий пример положил сюда:
github branch 03_all_work
В ветке main содержится работающий пример на commonjs, ветка 03_all_work - работающий пример на ESM.
Следует обратить внимание - что как написано в issue - код не будет работать в Node 19.
Возможно, как бы это ни было печально, следует избегать использования алиасов.