Как заставить TSLint разрешать зависимости косвенной типизации с рабочими пространствами Yarn?

Контекст

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

Проблема

Я столкнулся с проблемой, когда пакет B зависит от внешней библиотеки, но эта внешняя библиотека не имеет типизации, и поэтому пакет B создал свой собственный файл some-library.d.ts. При использовании tslint для линтинга пакета A этот файл настраиваемого определения правильно разрешается для выражений в пакете B, но не для выражений в пакете A, которые работают с типами из пакета B.

Я привел здесь упрощенный пример этой проблемы:

https://github.com/tommedema/tslint-yarn-workspaces

Суть его в следующем.

пакеты / a / src / index.ts

// tslint:disable:no-console

import { someDependedFn } from 'b'

export const someDependingFn = (): void => {
  const someNr = someDependedFn('pascal-case-me')
  console.log(someNr)
}

пакеты / b / src / index.ts

import camelCase from 'camelcase'

export const someDependedFn = (str: string): string => {
  const camelStr = camelCase(str, { pascalCase: true })

  return camelStr
}

пакеты / b / src / typings / 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 внутри пакета A, но это кажется очевидным нарушением разделения ответственности: пакет A не должен знать, что пакет B зависит от пакета camelcase, X или Y. Это только предполагается. чтобы узнать об общедоступном API пакета B, то есть о dependedFn.

Как я могу настроить tslint так, чтобы он правильно разрешал эти определения косвенной типизации при использовании рабочих пространств пряжи?


person Tom    schedule 19.07.2018    source источник


Ответы (1)


Вы можете заставить TSLint работать в вашем случае, удалив эти строки из tsconfig.json:

"baseUrl": "./packages",
"paths": {
  "*": ["./*/src"]
},

Эти строки сообщают компилятору TypeScript и TSLint, что они не должны обрабатывать ваши модули a и b как пакеты при их импорте, а должны разрешать отдельные файлы TypeScript, используя параметры baseUrl и paths, а затем компилировать отдельные файлы TypeScript. Это поведение задокументировано в разделе Module Resolution -> Path Mapping документации 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 правила. В реальных проектах обе команды будут использовать 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" скрипт в корне рабочей области package.json
  2. Иметь "watch": "tsc -p tsconfig.json -w" в пакетах рабочей области.
  3. Каждый раз, когда вы вносите изменения в свой проект, запускайте компилятор TypeScript в режиме наблюдения в каждом пакете, запустив npm run watch в корне рабочей области.
person Viktor Vlasenko    schedule 24.07.2018
comment
Интересно, но как же тогда я действительно смогу получить выгоду от моего монорепозитория? Т.е. как пакеты разрешают пути друг друга? - person Tom; 24.07.2018
comment
Они разрешают пути через node_modules. Ваш пакет a зависит от модуля b в package.json здесь: github.com/tommedema/tslint-yarn-workspaces/blob/, и поэтому Yarn устанавливает b в tslint-yarn-workspaces/package/node_modules как символическую ссылку. После этого компилятор tslint и typescript может разрешить b оттуда. - person Viktor Vlasenko; 24.07.2018
comment
Я понимаю, но это нарушит способность разрешать зависимости типов без предварительной компиляции. Это одна из основных причин использования разных tsconfig для tslint и редактора. - person Tom; 25.07.2018
comment
Я не вижу этого требования в вашем вопросе - вы не хотите сначала компилировать. И я не понимаю, где вы используете разные tsconfig для tslint и редактор в своем вопросе. Просьба уточнить. Я пытаюсь ответить на ваш вопрос. - person Viktor Vlasenko; 25.07.2018
comment
Я мог бы добавить это к вопросу, если вы думаете, что так лучше. Хотя в примере это уже работает. Опубликованное мной репо является упрощенным примером моей реальной настройки, основанной на github.com / Quramy / lerna-yarn-workspaces-example - там вы можете увидеть различные tsconfig для редактора и время компиляции. - person Tom; 25.07.2018
comment
Re: These lines tell TypeScript compiler and TSLint that they should not treat your modules a and b as packages when you import them, but rather they should resolve individual TypeScript files using baseUrl and paths parameters and then compile individual TypeScript files. это похоже на поведение, которое я действительно хочу. Вопрос, я думаю, заключается в том, почему это нарушает разрешение зависимостей 2-й степени. - person Tom; 25.07.2018
comment
Я бы определенно не рекомендовал подход с отображением путей для соединения пакетов друг с другом. При таком подходе вы меняете механизм разрешения со стандартного на с отображением пути, который отличается, и многие инструменты не ожидают, что вы импортируете пакеты с указанием пути. Так что у вас будут всевозможные неприятности. Скорее я бы рекомендовал использовать обычный поток, когда вы запускаете компилятор машинописного текста в режиме просмотра внутри каждого пакета через Lerna во время разработки. - person Viktor Vlasenko; 25.07.2018
comment
В моем проекте TypeScript в Yarn Workspaces github.com/sysgears/domain-schema я начал с этого шаблон, а также github.com/Quramy/lerna-yarn-workspaces-example Но после того, как я увидел все проблемы с инструментами из-за использования нестандартной разводки пакетов через отображение пути, мне пришлось избавиться от отображения пути, и теперь процесс разработки стал очень плавным. - person Viktor Vlasenko; 25.07.2018
comment
Возвращаясь к вашему комментарию: вопрос, я думаю, заключается в том, почему это нарушает разрешение зависимостей 2-й степени. Ответ - в своем проекте вы используете tsconfig.json для своего tslint и не используете tsconfig.json для компиляции. tslint под капотом использует компилятор для проверки исходного кода, когда вы указываете его на tsconfig.json. Если вы начнете использовать tsconfig.json внутри своего npm run build скрипта, вы также получите ошибки относительно типов 2-й степени. И причину, по которой вы их получите, я описал в своем ответе - модули с отображением путей, скомпилированные по-разному по дизайну. - person Viktor Vlasenko; 25.07.2018