isolatedDeclarations
是 TypeScript 中的一个编译选项,要求对导出内容进行充分类型注释,以便其他工具能够快速生成声明文件。
声明文件(.d.ts
)向 TypeScript 描述现有库和模块所具有的 API 。声明文件不会包含函数实体等实现细节。发布声明文件是为了让 TypeScript 能够高效地检查您对库的使用情况,而无法分析库本身。虽然可以手写声明文件,但是一般会使用 --declaration
编译选项从源文件自动生成声明文件,因为这样可以自动避免类型错误,也更简单。
TypeScript 编译器及其 API 始终负责生成声明文件的工作;然而,有些情况下,您可能希望使用其他工具,或者传统的构建工具无法满足需求。
场景一:更快的声明文件生成工具
想象一下,如果你想开发一个更快的工具来生成声明文件,可能是作为发布服务的一部分或者一个新的打包工具。虽然现在有很多超快的工具可以把 TypeScript 转换成 JavaScript,但在把 TypeScript 转换成声明文件方面,情况就没那么好了。这是因为 TypeScript 的类型推断特性让我们可以不明确声明类型来写代码,这就导致生成声明文件变得比较复杂。
让我们看看一个简单示例,将两个导入变量连接到一起的函数:
// util.ts export let one = "1"; export let two = "2"; // add.ts import { one, two } from "./util"; export function add() { return one + two; }
即使我们只想生成 add.d.ts
,TypeScript 也需要进入到另一个导入的文件(util.ts
),推断 one
和 two
的类型是字符串,然后计算出两个字符串相加会返回一个字符串类型,这无形中拖慢了声明文件的生成速度。
// add.d.ts export declare function add(): string;
虽然类型推断对于开发者的体验很重要,但这也意味着生成声明文件的工具需要复制类型检查器的部分功能,包括推断和解析模块标识符以跟踪导入(import
)的能力。
场景二:并行声明文件生成与并行类型检查
想象一下,如果您有一个包含多个项目的 Monorepo 代码库,并且拥有一个希望能够更快地帮助您检查代码的多核 CPU。若能通过在不同核心上同时运行各个项目来进行并行检查,岂不美哉?
遗憾的是,我们并不能完全自由地进行并行处理。这是因为我们必须按照依赖关系的顺序构建这些项目,因为每个项目都需要检查其依赖项的声明文件。因此,必须首先构建依赖项,以生成相应的声明文件。TypeScript 的项目引用功能也是如此,它以“拓扑”依赖顺序构建项目集。
举例来说,如果我们有两个项目,分别名为 backend
和 frontend
,并且它们都依赖于一个名为 core
的项目,那么在 core
被构建并生成其声明文件之前,TypeScript 无法开始对 frontend
或 backend
进行类型检查。
如上图所示,可以看出我们存在一个瓶颈。尽管我们可以并行构建 frontend
和 backend
,但必须首先等待 core
完成构建后,这两个项目才能开始构建。
解决方案:明确类型
这两个场景的共同需求是,我们需要一个跨文件的类型检查器来生成声明文件。这对工具社区来说是一项较大的挑战。
举一个更复杂的例子,如果我们想要以下代码的声明文件:
import { add } from "./add"; const x = add(); export function foo() { return x; }
我们需要为 foo
生成一个签名。然而,这需要查看 foo
的实现。由于 foo
只是返回 x
,因此要获取 x
的类型,就需要查看 add
的实现。但这可能还需要查看 add
依赖项的实现,依此类推。由此可见,生成声明文件需要进行大量的逻辑处理,以确定可能并不局限于当前文件的不同位置的类型。
不过,对于寻求快速迭代和完全并行构建的开发人员来说,还有另一种思考这个问题的方法。声明文件只需要模块公共 API 的类型——换句话说,就是导出内容的类型。如果开发人员愿意明确写出他们导出内容的类型,工具就可以在不查看模块实现的情况下生成声明文件,而无需重新实现完整的类型检查器。
这就是编译选项 --isolatedDeclarations
的作用。--isolatedDeclarations
在模块无法在没有类型检查器的情况下可靠地进行转换时会报告错误。更直白地说,它会使 TypeScript 报告错误,如果某个文件在其导出部分的注释不充分时。
如果启用了 --isolatedDeclarations
编译选项,上面的例子出现如下错误:
export function foo() { // ~~~ // error! Function must have an explicit // return type annotation with --isolatedDeclarations. return x; }
为啥错误是必要的?
因为这意味着 TypeScript 可以
- 明确告知我们,其他工具在生成声明文件时是否会遇到问题
- 提供一个快速解决方案,以帮助添加这些缺失的注释
不过,这种模式并不要求在所有地方都添加类型注释。对于局部变量,可以忽略这些注释,因为它们不影响公共 API。例如,以下代码不会产生错误:
import { add } from "./add"; const x = add("1", "2"); // x 不会出现 error 信息,因为没有导出他,是内部的局部变量 export function foo(): string { return x; }
还有一些表达式,其类型的计算非常简单,对于这种情况,启用了 isolatedDeclarations
编译选项也不会报错:
// 'x' 上不会有报错信息 // 计算 number 类型非常简单,几乎不消耗性能 export let x = 10; // 'y' 上不会有报错信息 // 我们可以从 return 表达式中获取类型 export function y() { return 20; } // 'z' 上不会有报错信息 // 类型断言清楚地说明了类型是什么。 export function z() { return Math.max(x, y()) as number; }
使用 isolatedDeclarations
使用 isolatedDeclarations
的前提是要设置 declaration
或 composite
。
declaration
编译选项不需要过多解释,表示要生成声明文件的意思。
composite
编译选项则用于启用项目引用功能,使 TypeScript 能够对项目进行增量编译。启用此选项后,编译器会生成一些额外的输出文件,比如tsbuildinfo
文件,以记录项目的编译状态和依赖关系。具体可见 聊一聊 TypeScript 的工程引用 。
要注意的是,isolatedDeclarations
选项不会改变 TypeScript 生成声明文件的方式,仅影响错误报告的方式。而且,使用 isolatedDeclarations
也不会带来 TypeScript 编译上性能的提升。因此,还需要耐心地等待 TypeScript 未来在这一领域的发展。
此外,隔离声明(isolatedDeclarations
)仍然是一项新功能,TypeScript 团队正在积极致力于改善相关的用户体验,目前,一些场景,例如在类和对象字面量中使用计算属性声明,尚不支持隔离声明(isolatedDeclarations
)。
因此,isolatedDeclarations
应根据具体情况进行采用。在使用 isolatedDeclarations
时,开发者的体验可能会受到影响,因为他要求开发者为导出的 API 进行充分的类型注释,因此如果您的业务未涉及前面提到的两个场景,则可能并不是最佳选择。对于其他情况,isolatedDeclarations
利于优化和解锁不同并行构建策略。与此同时,如果你愿意接受相关权衡(降低一些开发体验),相信 isolatedDeclarations
可以成为提升构建性能的强大工具。
总结
isolatedDeclarations
是 TypeScript 中的一个编译选项,isolatedDeclarations
编译选项用于未来加快 TypeScript 生成类型声明文件的速度,他要求对导出的模块 API 进行充分的类型注释,以帮助其他工具可以快速生成声明文件(.d.ts
)。
现在使用
isolatedDeclarations
不能为 TypeScript 带来编译性能的提升,但是能帮助开发者写出类型更健壮的代码,因为他有更严格的类型检查
启用了 --isolatedDeclarations
编译选项后,如果你导出的模块 API 没有充分的类型注释,TypeScript 就会报错。
启用 --isolatedDeclarations
编译选项:
// util.ts export let one = "1"; export let two = "2"; // add.ts import { one, two } from "./util"; export function add() { return one + two; }
具体的报错为:
可以看到,启用了 --isolatedDeclarations
编译选项后,导出的模块 API 需要有显示的类型注释。
不过,对于非常简单的类型计算,TypeScript 不会报错:
参考
Isolated Declarations
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/typescriptbc/1260.html