TypeScript 允许在三斜杠 "types" 指令中使用相对路径会生成错误的定义,

83qze16e  于 4个月前  发布在  TypeScript
关注(0)|答案(2)|浏览(47)

我设法发布了一个模块,其中使用了错误的三斜杠指令,导致无法使用的类型定义。我认为Typescript在编译过程中生成声明时本应该捕获此错误。

TypeScript版本:3.8.0-dev.20200131
搜索词:

三斜杠指令相对路径

代码

让我们构建一个最小的应用,它消耗自定义类型定义。为了方便起见,我会将其放在types中,并指定typeRoots,但这也适用于可能出现在node-modules/@types/some_module中的已发布的模块。

├── package.json
├── tsconfig.json
├── src
|   └── main.ts
└── types
    └── package
        ├── index.d.ts
        └── type.d.ts
  • package.json*
{
  "name": "reference-type-paths",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "rm -rf dist/*; tsc"
  },
  "devDependencies": {
    "typescript": "^3.8.0-dev.20200131"
  }
}
  • tsconfig.json*
{
  "compilerOptions": {
    "target": "ES2019",
    "module": "commonjs",
    "declaration": true,
    "outDir": "./dist",
    "strict": true,
    "typeRoots": ["./types"]
  }
}

我们设置了一些TS文件,以使用模块中定义的自定义类型。

  • src/main.ts*
export class Container {
    readonly data: Optional<string>;
}

不幸的是,我们的模块错误地使用了带有路径的types三斜杠指令。

  • types/package/index.d.ts*
/// <reference types="./type" />
  • types/package/type.d.ts*
declare type Optional<T> = T | null | undefined;

最后,我们运行tsc

预期行为:

Typescript不应该发出包含无效“类型”路径的声明文件。在使用路径(或相对于typeRoots的路径)时,应将/// <reference types=作为错误在编译过程中捕获,以防止生成无法使用的声明文件。
我们有/// <reference path=,这里应该使用它。如果types/package/index.d.ts包含/// <reference path="./type.d.ts" />,Typescript会产生:

  • dist/main.d.ts*
/// <reference types="package" />
export declare class Container {
    readonly data: Optional<string>;
}

然后正确解析。
或者,可能会生成相对于typeRoots目录的路径:

  • dist/main.d.ts*
/// <reference types="package/type" />
export declare class Container {
    readonly data: Optional<string>;
}

https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-types- states:
解析这些包名的过程与解析导入语句中的模块名的过程相似。很容易想到,三斜杠引用类型指令就像是对声明包的导入。
这并不意味着在三斜杠类型引用中使用相对路径是不合适或危险的。

实际行为:

不幸的是,实际上得到的是模块的三斜杠指令保留的相对路径。

  • dist/main.d.ts*
/// <reference types="./type" />
export declare class Container {
    readonly data: Optional<string>;
}

这个定义是无法使用的。如果我们发布它,我们模块的消费者将看到错误,因为type相对于他们的typeRoots不存在。
这特别令人沮丧,因为只有在模块具有错误指令的二级依赖项中才会被注意到。在这个例子中,我可以依赖于package,显然可以成功编译并生成自己的声明,发布它们,然后有人依赖于我的包并尝试消费我的声明时遇到编译错误。

Playground链接:

不可能,取决于生成d.ts声明文件。

sdnqo3pr

sdnqo3pr1#

解决方法

TS 3.8.x

如果我添加一个类型导入:

  • src/main.ts*
import type { Optional } from "package";

export class Container {
    readonly data: Optional<string>;
}

那么我就可以得到一个可用的定义文件:

  • dist/main.d.ts*
/// <reference types="package" />
export declare class Container {
    readonly data: Optional<string>;
}

TS 3.7.5, 3.7.3

我没有阻止发布包含不可达路径的定义的方法,但是依赖项可以使用自己的三斜杠声明来解决这个问题,例如,如果有人从这个例子中安装了main.d.ts作为依赖项,将/// <reference types="package/type"/>添加到他们的.ts文件中可以让他们编译通过。

7vhp5slm

7vhp5slm2#

关于这个的更新情况?

编辑:我不想显得粗鲁,但我们也遇到了同样的问题。我们希望这个问题能得到解决,如果有办法帮助解决的话,我们会很乐意知道。

相关问题