Мне пришлось решить эту проблему для моей библиотеки журналов, winston-jsonl-logger
.Он дополняет глобальную область видимости глобальной переменной с именем logger
.Я согласен, что это одна из самых сложных (если не самая трудная) проблема в TypeScript, не в последнюю очередь из-за отсутствия достаточного количества документации.В этом примере я создаю библиотеку, которая использует как глобально видимые («скрипт»), так и модульно-видимые («модуль») типы.Чтобы уточнить, что официальная терминология :
В TypeScript, как и в ECMAScript 2015, любой файл, содержащий import
или export
верхнего уровня, считается модулем.И наоборот, файл без каких-либо объявлений import
или export
верхнего уровня обрабатывается как сценарий, содержимое которого доступно в глобальной области (и, следовательно, также для модулей).
Структура каталогов
Моя папка src
переносится в dist
.test
игнорируется при трансплантации.
Крайне важно, чтобы ваши наборы имели имя index.d.ts
и были вложены в папку, имя которой совпадает с именем вашего проекта (что, вероятно, строго соответствует имени, указанному в * 1023).*).Это то, что структура будет искать typeRoots
.
.
├── README.md
├── dist
│ ├── Logger.d.ts
│ ├── Logger.js
│ ├── Logger.js.map
│ ├── initLoggers.d.ts
│ ├── initLoggers.js
│ └── initLoggers.js.map
├── package-lock.json
├── package.json
├── src
│ ├── Logger.ts
│ └── initLoggers.ts
├── test
│ └── index.ts
├── tsconfig.json
└── typings
└── winston-jsonl-logger
└── index.d.ts
«скриптовые» наборы
Типы скриптов - это те, в которых отсутствует верхний уровень import
или export
.Они будут видны в глобальном масштабе в проектах, которые их потребляют.
Конечно, поскольку они не могут использовать объявления верхнего уровня import
, они ограничены в своей описательности;Вы можете часто видеть много any
используемых здесь.Это проблема, которую я пытаюсь решить в своем собственном вопросе .
// typings/index.d.ts
declare namespace NodeJS {
export interface Global {
logger?: any;
log?: any;
logInfo?: any;
}
}
Если вы используете logger
в глобальной области видимости, она будет напечатана как any
now.
печатания 'module'
При печатании модуля можно использовать import
или export
верхнего уровня, но они будут видны только в том случае, если модуль будет импортирован в проект.то есть они не видны глобально по всему проекту.
// initLoggers.ts
import {Logger} from "./Logger";
import {LogEntry, Logger as WinstonLogger} from "winston";
// Now we can be more descriptive about the global typings
declare global {
const logger: Logger;
// LogEntry's interface: { level: string, message: string, data?: any }
function log(entry: LogEntry): WinstonLogger;
function logInfo(message: string, data?: any): WinstonLogger;
}
export function initLoggers(){
global.logger = new Logger();
global.log = logger.log.bind(logger);
global.logInfo = (message: string, data?: any) => {
return logger.log({ level: "info", message, data });
}
}
Если вы используете logger
в глобальной области видимости, все равно будет напечатано как any
, но по крайней мере global.logger
будет иметь правильные наборы.
Чтобы гарантировать, что эти типы будут видны в вашем проекте my-project
, убедитесь, что my-project
импортирует этот файл из winston-jsonl-logger
;Я делаю это в точке входа моего приложения.
package.json
Я не использовал поле typings
или types
(возможно, указание "typings": "typings/winston-jsonl-logger/index.d.ts"
означало бы, что пакеты неЯ не могу явно объявить путь к моим наборам; я не знаю), но я сделал , не забудьте распространить свою папку с наборами.
{
"name": "winston-jsonl-logger",
"version": "0.5.3",
"description": "TypeScript JSONL logger.",
"main": "dist/Logger.js",
"files": [
"dist",
"typings"
],
"devDependencies": {
"@types/logform": "1.2.0",
"@types/node": ">=9.6.21",
"ts-node": "7.0.1",
"typescript": "3.1.1"
},
"dependencies": {
"winston": "3.2.0",
"winston-daily-rotate-file": "3.6.0",
"winston-elasticsearch": "0.7.4"
}
}
Пропущенные поля: repository
, keywords
, author
, license
, homepage
, publishConfig
и scripts
;в противном случае это все.
tsconfig.json
Для самой библиотеки
Ничего особенного.Просто ваши стандартные tsc --init
значения по умолчанию.
Для проектов, использующих lib
Просто убедитесь, что вы добавили typeRoots
выглядит следующим образом:
{
"compilerOptions": {
// ...All your current fields, but also:
"typeRoots": [
"node_modules/@types",
"node_modules/winston-jsonl-logger/typings/winston-jsonl-logger"
]
}
}
Если выВы используете ts-node
Здесь есть другие ошибки.По умолчанию ts-node
игнорирует типизацию сценариев и импортирует только потомки импорта начального уровня (причина этого в скорости / эффективности).Вы можете принудительно разрешить импорт так же, как tsc
, установив переменную окружения: TS_NODE_FILES=true
.Да, тесты будут выполняться медленнее, но, с другой стороны, это будет работать вообще.
Если вы используете ts-node
через командную строку, объявите переменную окружения TS_NODE_FILES
равной true
.Мне также пришлось объявить TS_NODE_CACHE
как false
из-за необъяснимой ошибки кэша в ts-node
(версия 7.0.1 - все еще может быть проблемой) при разрешении импорта / зависимостей.
TS_NODE_FILES="true" TS_NODE_CACHE="false" TS_NODE_PROJECT="./tsconfigs/base.json" /usr/bin/nodejs --require ts-node/register --inspect=127.0.0.1:9231 src/index.ts --myCustomArg="hello"
Я обычно использую ts-node
, потому что я тестирую с Мокко.Вот как я передаю переменные окружения в ts-node
от Mocha:
// mocha.env.js
/* From: https://github.com/mochajs/mocha/issues/185#issuecomment-321566188
* Via mocha.opts, add `--require mocha.env` in order to easily set up environment variables for tests.
*
* This can theoretically be made into a TypeScript file instead, but it seemed to not set the env variable when I tried;
* perhaps it failed to respect the order of the --require declarations. */
process.env.TS_NODE_FILES = "true"; // Force ts-node to use TypeScript module resolution in order to implictly crawl ambient d.ts files
process.env.TS_NODE_CACHE = "false"; // If anything ever goes wrong with module resolution, it's usually the cache; set to false for production, or upon any errors!
Надеюсь, это поможет!