今天读antd源码读到了components/index.tsx文件,看见里面大量的使用export type ** from ‘./’ 和 export ** from ‘./’, image.png
感觉和以前的export 的用法不太一样
在创建 JavaScript 模块时,export 语句用于从模块中导出实时绑定的函数、对象或原始值,以便其他程序可以通过 import 语句使用它们。被导出的绑定值依然可以在本地进行修改。在使用 import 进行导入时,这些绑定值只能被导入模块所读取,但在 export 导出模块中对这些绑定值进行修改,所修改的值也会实时地更新。
存在两种 exports 导出方式:
1、命名导出(每个模块包含任意数量)
// 导出单个特性
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}
// 导出列表
export { name1, name2, …, nameN };
// 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };
// 解构导出并重命名
export const { name1, name2: bar } = o;
// 默认导出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
// 导出模块合集
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;
2、默认导出(每个模块包含一个)
// 导出事先定义的特性
export { myFunction, myVariable };
// 导出单个特性(可以导出 var,let,
//const,function,class)
export let myVariable = Math.sqrt(2);
export function myFunction() { ... };
为了使模块导入变得可用,在一个父模块中“导入/导出”这些不同模块也是可行的。也就是说,你可以创建单个模块,集中多个模块的多个导出。
export { default as function1,
function2 } from 'bar.js';
可以转换成常规写法
import { default as function1,
function2 } from 'bar.js';
export { function1, function2 };
在导入默认导出的文件时需要注意
import DefaultExport from 'bar.js'; // 有效的
export DefaultExport from 'bar.js'; // 无效的
export { default as DefaultExport } from 'bar.js'; 有效
通过前面的了解,export type可以写成如下
export type { AffixProps } from './affix';
转换
import type { AffixProps } from './affix';
export AffixProps
首先说tsc
的编译, 在我们日常写代码的过程中, 通常会使用import
去导入一些类型或者值, 比如下面的写法:
// ./foo.ts
interface Options {
// ...
}
export function doThing(options: Options) {
// ...
}
// ./bar.ts
import { doThing, Options } from "./foo.js";
function doThingBetter(options: Options) {
// do something twice as good
doThing(options);
doThing(options);
}
上面的代码中, doThing
是作为一个值被导入, Options
作为一个类型被导入, 这样同时导入其实很方便, 因为我们不用担心我们导入的是什么, 只需要知道我要用它, import
就完事了, 哪怕我同时import
的是一个类型和一个实际值也没有关系.
但我们能够同时import
一个值和一个类型, 是因为一个叫**import elision
**(导入省略)的功能在起作用.
当Typescript
进行代码编译时, 发现Options
是作为一个类型被导入的, 就会自动在生成的JS
代码中删除掉它的导入, 所以最终生成的是类似于(类似, 用于解释说明, 但可能非实际输出代码)下面的JS
代码:
// ./foo.js
export function doThing(options: Options) {
// ...
}
// ./bar.js
import { doThing } from "./foo.js";
function doThingBetter(options) {
// do something twice as good
doThing(options);
doThing(options);
}
可见, 所有跟类型相关的代码, 都在最终编译生成的文件里被删除了, 所以我们直接通过import
和export
来导入/导出值和类型的写法是很方便的, 但是这么写, 也会存在一些问题.
利用3.8 release notes中例子来做说明, 在某些情况下, 可能会出现一些比较模棱两可的代码:
// ./some-module.ts
export interface MyThing {
name: string;
}
// ./src.ts
import { MyThing } from "./some-module.ts";
export { MyThing };
复制代码
比如上面的例子, 如果把我们的分析仅仅限定在这个文件里, 仅凭文件里的这两行代码, 我们是难以分析出MyThing
到底是应该是一个值, 还是一个类型的.
如果MyThing
仅仅是作为一个类型而存在, 那么使用Babel
或者ts.transpileModule
API这样的工具最终编译出的javascript
代码是不能够正确的运行的, 编译生成的代码如下:
// ./some-module.js
----empty----
// ./src.js
Object.defineProperty(exports, "MyThing", {
enumerable: true,
get: function () {
return _test.MyThing;
}
});
var _test = require("./test1");
复制代码
最终生成的src.js
文件中对MyThing
的导入和导出都会被保留, 而在some-module.js
文件中, MyThing
仅作为一个类型而存在, 会在编译过程中被删除, 所以最终some-module.js
文件是空的(可能会存在别的编译过程中的代码, 但是MyThing
的定义会被删除), 这样的代码会在运行时产生报错.
Typescript
的import elision
功能会删除掉仅作为类型使用的import
导入, 这在导入某些具有副作用的模块时, 会造成特别明显的影响, 让使用者不得不再写一个额外的语句去专门导入副作用:
// 因为import elision的功能, 这行代码在最终生成的js代码中会被删除
import { SomeTypeFoo, SomeOtherTypeBar } from "./module-with-side-effects";
// 这行代码要一直存在
import "./module-with-side-effects";
复制代码
import type
基于上面的问题, Typescript 3.8
中引入了import type
, 希望能够用一种更加清晰易懂的方式来控制某一个导入是否要被删除掉.
import { MyThing } from "./some-module.ts";
export { MyThing };
复制代码
上面的例子就是我们在问题1中介绍过的, 像Babel
这样的编译工具是不能够准确的识别MyThing
到底是一个值还是类型的, 因为Babel
在编译的过程中, 一次只会处理一个文件.
所以这种时候, 我们就需要一种方式, 来准确的告诉正在编译这个文件的编译工具, 现在使用import type
和export type
导入和导出的MyThing
就是一个类型, 你完全可以在编译的时候把这段代码省略(删除)掉.
import type { MyThing } from "./some-module.ts";
export type MyThing;
复制代码
使用import type
和export type
导入和导出的类型只能在类型上下文中使用, 不能作为一个值来使用.
最后关于import type部分我主要是引用于https://juejin.cn/post/7111203210542448671