如何让TSLint解决与Yarn工作区的间接类型依赖关系?

Tom*_*Tom 11 typescript tslint yarnpkg yarn-workspaces

上下文

纱线工作空间提供了一种依赖单声道包装的便捷方式.当包A依赖于包B时,包B中定义的接口等在包A中被适当地解析.

问题

我面临的问题是,如果包B依赖于外部库,但外部库缺少打字,因此包B创建了自己的some-library.d.ts文件.当使用tslintlint包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)
}
Run Code Online (Sandbox Code Playgroud)

包/ B/src目录/ index.ts

import camelCase from 'camelcase'

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

  return camelStr
}
Run Code Online (Sandbox Code Playgroud)

包/ B/src目录/分型/驼峰/ 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
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您将目录更改为打包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'.
Run Code Online (Sandbox Code Playgroud)

TSLint不识别包B所依赖的类型,但它只是在从包A运行tslint时抱怨这个(不是预期的).在包B内,tslint不会抱怨(如预期的那样).

当然我可以手动添加camelcase内部包A的类型,但这似乎明显违反了关注点的分离:包A不应该知道包B依赖于包camelcase,或X或Y.它只是应该了解包B的公共API,即dependedFn.

如何设置tslint,以便在使用纱线工作区时正确解析这些间接输入定义?

Vik*_*nko 1

您可以通过从以下位置删除这些行来使 TSLint 在您的情况下工作tsconfig.json

"baseUrl": "./packages",
"paths": {
  "*": ["./*/src"]
},
Run Code Online (Sandbox Code Playgroud)

这些行告诉 TypeScript 编译器和 TSLint,在导入模块a和包时,它们不应将其视为包,而是应使用和参数解析各个 TypeScript 文件,然后编译各个 TypeScript 文件。此行为记录在 TypeScript 文档的模块解析 -> 路径映射部分中:bbaseUrlpaths

https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping

相反,如果我理解正确的话,您希望将ab视为独立的包。要实现此目的,您应该删除路径映射,然后 TypeScript 和 TSLint 会将它们视为 npm 包。

更新(基于评论中的讨论)

在您的项目中,您使用命令运行 TSLint:

tslint -p tsconfig.json 但您使用命令运行 TSC:

tsc src/index.ts --outDir dist

您的 TSLint 使用 TypeScript 编译器 API 根据tsconfig.json. 但你的 TypeScript 编译器不使用tsconfig.json规则。在实际项目中,这两个命令都会使用tsconfig.json

当您也开始使用tsconfig.json编译时,您将遇到与 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'
                    ~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为路径映射模块导入按设计不同编译,然后 根据第一部分中指定的node_modulesTypeScript 文档 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. 每当您对项目进行更改时,请通过npm run watch在工作区根目录中运行来在每个包中以监视模式启动 TypeScript 编译器。