Как заставить TSLint разрешать косвенную типизацию с помощью рабочих областей Yarn?
контекст
Рабочие пространства пряжи предоставляют удобный способ зависеть от пакетов в моно-репо. Когда пакет A зависит от пакета B, интерфейсы и т. Д., Определенные в пакете B, соответственно разрешаются в пакете A.
проблема
Я сталкиваюсь с проблемой, когда пакет B зависит от внешней библиотеки, но во внешней библиотеке нет типирования, и поэтому пакет B создал свой собственный some-library.d.ts
файл. Когда используешь tslint
что касается пакета A, этот пользовательский файл определений разрешается правильно для выражений в пакете B, но не для выражений в пакете A, которые работают с типами из пакета B.
Я поместил упрощенный пример этой проблемы здесь:
https://github.com/tommedema/tslint-yarn-workspaces
Суть его заключается в следующем.
пакеты / а / SRC / index.ts
// tslint:disable:no-console
import { someDependedFn } from 'b'
export const someDependingFn = (): void => {
const someNr = someDependedFn('pascal-case-me')
console.log(someNr)
}
пакеты / б / SRC / index.ts
import camelCase from 'camelcase'
export const someDependedFn = (str: string): string => {
const camelStr = camelCase(str, { pascalCase: true })
return camelStr
}
пакеты / B / SRC / типизация / CamelCase / index.d.ts
// Type definitions for camelcase 5.0
// Project: https://github.com/sindresorhus/camelcase
// tslint:disable only-arrow-functions completed-docs
declare module 'camelcase' {
export default function camelCase(
strs: string | string[],
options: {
pascalCase?: boolean
}
): string
}
Теперь, если вы измените каталог на пакет a
и беги yarn build
, это работает просто отлично. Но если вы бежите yarn lint
, это бросит:
$ tslint -p tsconfig.json
ERROR: packages/b/src/index.ts[4, 20]: Unsafe use of expression of type 'any'.
ERROR: packages/b/src/index.ts[6, 10]: Unsafe use of expression of type 'any'.
TSLint не распознает типизации, от которых зависит пакет B, но жалуется на это только при запуске tslint из пакета A (не ожидается). Внутри упаковки Б, Цлинт не жалуется (как и ожидалось).
Вопрос
Конечно, я мог бы вручную добавить набор camelcase
внутри пакета A, но это кажется очевидным нарушением разделения интересов: пакет A не должен знать, что пакет B зависит от пакета верблюда, или X или Y. Он должен знать только об открытом API пакета B, т.е. dependedFn
,
Как настроить tslint таким образом, чтобы он правильно разрешал эти определения косвенной типизации при использовании рабочих областей пряжи?
1 ответ
Вы можете заставить TSLint работать в вашем случае, удалив эти строки из tsconfig.json
:
"baseUrl": "./packages",
"paths": {
"*": ["./*/src"]
},
Эти строки сообщают компилятору TypeScript и TSLint, что они не должны обрабатывать ваши модули a
а также b
как пакеты, когда вы импортируете их, но они должны разрешать отдельные файлы TypeScript, используя baseUrl
а также paths
параметры, а затем компилировать отдельные файлы TypeScript. Это поведение описано в разделе "Разрешение модуля" -> "Сопоставление пути" документации TypeScript:
https://www.typescriptlang.org/docs/handbook/module-resolution.html
Вместо этого, если я вас правильно понял, вы хотите лечить a
а также b
в качестве независимых пакетов. Чтобы добиться этого, вы должны удалить отображение пути, и тогда TypeScript и TSLint будут обрабатывать их как пакеты npm.
ОБНОВЛЕНИЕ (на основе обсуждения в комментариях)
В вашем проекте вы запускаете TSLint с помощью команды:
tslint -p tsconfig.json
но вы запускаете TSC с помощью команды:
tsc src/index.ts --outDir dist
Ваш TSLint использует API-интерфейс компилятора TypeScript для выполнения проверок на основе правил из tsconfig.json
, Но ваш компилятор TypeScript не использует tsconfig.json
правила. В реальных проектах обе команды будут использовать tsconfig.json
Когда вы начинаете использовать tsconfig.json
и для компиляции вы получите ту же проблему с разрешением типов зависимостей 2-й степени, что и для TSLint:
$ tsc -p tsconfig.json
../b/src/index.ts:1:23 - error TS7016: Could not find a declaration file for module 'camelcase'. '/home/victor/work/tslint-yarn-workspaces.org/node_modules/camelcase/index.js' implicitly has an 'any' type.
Try `npm install @types/camelcase` if it exists or add a new declaration (.d.ts) file containing `declare module 'camelcase';`
1 import camelCase from 'camelcase'
~~~~~~~~~~~
Это происходит из-за того, что импортированные по путям модули импортируются по-разному, а затем импортируются из node_modules
согласно документации TypeScript https://www.typescriptlang.org/docs/handbook/module-resolution.html как указано в первой части ответа.
Я бы порекомендовал использовать обычный импорт в вашем проекте, чтобы не было проблем с инструментами:
- Есть
"watch": "lerna run --parallel -- watch"
скрипт в корне рабочей областиpackage.json
- Есть
"watch": "tsc -p tsconfig.json -w"
в рабочих пакетах. - Всякий раз, когда вы вносите изменения в свой проект - запускайте компилятор TypeScript в режиме наблюдения в каждом пакете, запустив
npm run watch
в корне рабочей области.