Как заставить 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 как указано в первой части ответа.

Я бы порекомендовал использовать обычный импорт в вашем проекте, чтобы не было проблем с инструментами:

  1. Есть "watch": "lerna run --parallel -- watch" скрипт в корне рабочей области package.json
  2. Есть "watch": "tsc -p tsconfig.json -w" в рабочих пакетах.
  3. Всякий раз, когда вы вносите изменения в свой проект - запускайте компилятор TypeScript в режиме наблюдения в каждом пакете, запустив npm run watch в корне рабочей области.
Другие вопросы по тегам