纯类型导入的真正用例是什么,证明增加的冗长是合理的?

问题描述 投票:0回答:2

当我升级到最新版本的 TypeScript 并发现仅类型导入时,我认为它非常酷并开始在任何地方使用它。

设置仅类型导入一段时间后,我很快意识到我得到了预期的更多冗长和“脏代码”。

没有仅类型导入:

import { SomeType, someFunction, SomeClassToInstantiate } from '@my-app/lib1';
import { OtherType, otherFunction, OtherClassToInstantiate } from '@my-app/lib2';

仅导入类型:

import type { SomeType } from '@my-app/lib1';
import { someFunction, SomeClassToInstantiate } from '@my-app/lib1';
import type { OtherType } from '@my-app/lib2';
import { otherFunction, OtherClassToInstantiate } from '@my-app/lib2';

基本上,我的很多导入都会重复,并且很难跟踪我是否以正确的方式导入所有内容(如果我将其导入为我在文件中实际使用的类型,则编译器会进行标记 - 但反之则不会)等等,我没有找到任何工具来标记导入仅用作类型,应该切换到仅类型导入)。

也许我更注意到这个问题,因为我正在使用 NX 并且我的应用程序的很多代码都来自库的桶文件;即,经常发生这样的情况:两者必须从同一模块导入类型和非类型。

所以我想知道,在任何地方使用仅类型导入可以得到什么实际优势?是否在某些特定情况下使用它肯定有帮助,并且在所有其他情况下都可以绕过它?

如果我上一个问题的答案是应该在可能的情况下始终使用它,那么您是否知道在可以使用类型导入时强制执行类型导入的任何 linting 规则?

我不喜欢导入量比以前几乎翻倍的混乱,甚至不知道它们始终分布在各处的常规/仅类型导入中。

typescript lint type-only-import-export
2个回答
14
投票

是否有特定情况下使用它肯定有帮助,并且在所有其他情况下都可以绕过它?

尽管无条件地使用仅类型导入并没有什么坏处(为了一致性),但确实存在需要它们的特定情况。下表比较了不同选项组合的用例:

isolatedModules
/
preserveValueImports
true
false
true
仅需要类型导入,因为单文件处理缺乏完整的类型系统信息来消除类型导入。
示例
如果导出类型,则需要仅导出类型。
示例
false
优先的、仅类型的导入将被省略 优先的、仅类型的导入将被省略

它们最常见的用例是同时启用

isolatedModules
preserveValueImports
,这是明确记录的

与isolatedModules结合使用时:导入的类型必须标记为仅类型,因为一次处理单个文件的编译器无法知道导入是否是未使用的值,或者是必须删除以避免运行时的类型崩溃。

另一个用例是启用

isolatedModules
模块(无论
preserveValueImports
选项如何),并且您正在导出类型(导入或未导入),这也已记录

单文件转译器不知道 someType 是否生成值,因此导出仅引用类型的名称是错误的。

如果您的配置启用了

preserveValueImports
,则仅类型导入对于强制省略仅在类型位置中使用的导入也很有用,如果保留这些导入,则不会出现运行时错误(在下面的示例中,
import type
将允许编译器完全消除导入):

import { ESLint } from "eslint"; // ESLint is a class
let esl: ESLint;
export { esl };

至于 linting,

@typescript-eslint/eslint-plugin
对于 ESLint 有 2 条规则来管理仅类型导入和导出的使用:


需要注意的是,从 4.5 开始,TypeScript 在导入名称上添加了类型修饰符,这些修饰符是专门为解决仅类型导入的冗长问题而添加的,因此您不再需要拆分导入:

import { someFunction, SomeClassToInstantiate, type SomeType } from '@my-app/lib1';

0
投票

我刚刚完成了我的有趣阅读所有相关问题/提案/PR。这是给懒惰读者的善意总结:

  1. 仅类型导入/导出是为了解决特定问题/麻烦而提出的功能。这不仅仅是为了好玩或提供方便:TypeScript 过去很难同时满足两个阵营:

camp1:请不要帮我删除you-guess-未使用的导入,因为我想要副作用

// input
import { OnlyUsedAsType } from "sideEffectMod";
import { UsedAsValue } from "basicMod";

declare const a: OnlyUsedAsType;
const b = UsedAsValue;

// output                       <---- oh no, `sideEffectMod` is removed!
import { UsedAsValue } from "";
const b = UsedAsValue;

camp2:请帮我删除 you-guess 使用的导入,因为我是

isolatedModules
上的非类型检查转译器:

import { SomeType } from "someModule"; // <---- oh no, I have to assume it is not a type
export { SomeType };                   // <---- too.
let x: SomeType | undefined;

export { SomeOtherType } from "someModule"; // <---- too.
  1. 因此,他们决定创建 1) 一种新语法——仅类型导入/导出,即
    import type {...}
    和 2)
    preserve
    副作用的选项,即
    importsNotUsedAsValues

那么,幸福的结局,因为两个阵营都满意,对吧......?没有。但为了初学者友好,我们就到此结束吧:)

© www.soinside.com 2019 - 2024. All rights reserved.