引入ts类型

在我们刚开始学习ts的时候,常常是会创建一个types.ts文件,然后在里面声明一个类型并导出:

export interface User {
  name: string;
  age: number;
}

使用的时候通过import导入:

import { User } from "./types";

const user:User = {
  name: "a",
  age: 18
};

很高兴你已经学会了如何引入ts类型,教程结束!

当然,这是骗你的,但是这种用法确实是最开始ts所提供的,你不能说它错了,我们需要思考一下ts是如何被转为js,就会发现一些问题。

在大部分的项目配置中,我们总是在编辑器里使用ts的类型校验,而在运行时使用的是babel进行编译转换,也就是说在静态编译阶段使用的是编辑器,比如vscode的内置ts检测功能,代码实际上是通过babel进行编译的,这是一种很常见的做法。

在ts的3.8之前的阶段,babel对于ts的类型引入在转换时并不会删除它,因为ts并没有提供清晰的方式来表明import引入的是一个类型声明,这就意味着import { User } from "./types"写法会被保留下来,只是说会编译成引入一个不存在的导出,从上面的给的代码例子上看,好像也没什么问题。

这里我们就要了解一个新名字:模块副作用

在JavaScript中,模块副作用通常指在模块文件中,除了定义变量、函数、类等导出外,还有一些直接执行的代码,这些代码可能会改变全局变量、改变其他模块的导出项等等,这些操作的结果就是副作用。

转换成代码示意:

export interface User {
  name: string;
  age: number;
}

window.abc = {
  ...
}

此时window.abc的操作就是副作用。

如果babel在转换的时候没有将import { User } from "./types"去除,就有可能导致出现问题,因为window.abc我们可能是故意的,在某个地方导入时需要这么做,但是在其他地方引入User并不需要这么做,从而产生了很奇怪的问题!

事实上正式的项目可能这种问题会更加隐晦!

为了解决这个问题,ts在3.8之后,增加了一种新的声明引入类型的方式:

import type { User } from "./types";

我们明确声明引入的是一个类型,此时babel就能很明确的知道这段代码的意义,从而在转换的时候会进行删除处理。

问题被完美解决,皆大欢喜。

但是在后续的开发中,我们又发现,我们往往要从一个统一的入口里引入很多东西,比如:

import { SomeFunction } from "./module";
import type { SomeType } from "./module";

这种写法很繁琐,在引入的值是少部分的时候,需要书写两行代码,有什么办法可以提高引入的便利性呢?

在ts 4.5版本的时候,加入了一种新的类型引入方式:inline import types

import { type SomeType, SomeFunction } from "./module";

我们可以通过内联的方式引入,从而提高了代码的可读性和编写的便利性。

eslint规范

你需要先安装一个eslint插件:

npm i @typescript-eslint/eslint-plugin -D

完毕后配置一下eslint

{
  "plugins": [
    "@typescript-eslint"
  ],
  "extends": [
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "@typescript-eslint/consistent-type-imports": "error",
    "@typescript-eslint/consistent-type-exports": "error"
  }
}

@typescript-eslint/consistent-type-imports表示引入类型时必须加上type或者使用内联type。

@typescript-eslint/consistent-type-exports表示导出类型时必须是:export type UserId或者export interface User的方式,这个其实配不配都可以,类型导出不就这样嘛。

建议是开启eslint的自动修复功能,vscode安装插件 ESLint ,然后在设置里搜索 eslint auto fix

设置on开启即可,这样每次保存的时候会自动进行eslint修复。

动态导入

对于动态导入的情况下,@typescript-eslint/consistent-type-imports会出现问题,我们需要调整一些规则定义:

{
  "plugins": [
    "@typescript-eslint"
  ],
  "extends": [
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "@typescript-eslint/consistent-type-imports": [
      "error",
      { disallowTypeAnnotations: false }
    ],
    "@typescript-eslint/consistent-type-exports": "error"
  }
}

示例代码:

type T = import('Foo').Foo;
const x: import('Bar') = 1;

通过import动态引入的类型就不会报错了,如果你项目中用不到这种方式,事实上大部分情况下是用不到的,就没必要这么写,等用到了再改。

ts 5.0的新问题

在ts5.0的时候,重新改写了编译方式,对于内联type类型,会出现意料之外的情况:

import { type User } from "./types";

当我们的import引入是一个全是内联type的时候,它会被编译为:

import {  } from "./types";

这就导致又会产生我们之前所说的模块副作用问题。

好在eslint提供了一个解决方式,配置一个rules:

{
  "rules": {
    "@typescript-eslint/no-import-type-side-effects": "error",
  }
}

@typescript-eslint/no-import-type-side-effects表示在类型引入时不要有副作用,配置之后配合eslint自动修复功能,它会将代码修正:

import { type User } from "./types";
// 修正后
import type { User } from "./types";

此时再被编译,就不会出现副作用的问题,整个类型引入在编译后会被删除。

分类: TypeScript 标签: type类型TypeScriptimportinterface

评论

暂无评论数据

暂无评论数据

目录