Как заставить TSLint разрешать косвенные типизирующие зависимости с рабочими пространствами пряжи?

контекст

Рабочие пространства пряжи обеспечивают удобный способ зависеть от пакетов в моно-репо. Когда пакет A зависит от пакета B, интерфейсы и т.д., Определенные в пакете B, соответствующим образом разрешаются в пакете A.

проблема

Я столкнулся с проблемой, если пакет B зависит от внешней библиотеки, но в этой внешней библиотеке отсутствуют типизации, и поэтому пакет B создал свой собственный файл some-library.d.ts. При использовании tslint to lint package 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 (не ожидалось). Внутри пакета B, tslint не жалуется (как и ожидалось).

Вопрос

Разумеется, я мог бы вручную добавить типовые camelcase верблюжьей 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#path-mapping

Вместо этого, если бы я понял вас правильно, вы хотите рассматривать 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. В реальных проектах -w orld обе команды будут использовать 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#path-mapping, как указано в первом часть ответа.

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

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