UMD 的包如何导出 TS 类型

在 TypeScript 里声明模块,最早是用 namespace 和 module 的语法,后来支持了 es module,类型和变量会用 import 来导入、用 export 导出。

比如你写了一个库,导出的变量叫 Guang,它下面有 name 和 age 两个属性,所以你是这样声明类型的:

export default Guang;

declare namespace Guang {
    export const name = 'guang';
    export const age = '20';
}

使用的时候用 import 来导入:

import Guang from 'xxx';

console.log(Guang.name, Guang.age);

这样是没啥问题。

但如果这个库除了支持 es module 的方式使用,还支持 umd 呢?

UMD 规范想必大家很熟悉了,就是判断是 CMD、AMD 还是全局变量的方式,然后用合适的模块规范导出模块的值:

UMD 的包如何导出 TS 类型

但这里面不包含 es module,因为它不是 api 而是语法。

那如果你构建出了 umd 规范的代码,使用者用 script 的方式给引入了:

UMD 的包如何导出 TS 类型

这样还能做类型提示和检查么?

不能了,因为你导出是用的 esm 的 export,只有 import 引入才会有类型提示和对应的检查。

那怎么办呢?

用 declare global 声明为全局类型?

declare global {
    namespace Guang {
        export const name = 'guang';
        export const age = '20';
    }
}

这样是能解决问题,但这样在 esm 模块里也不用 import 就可以直接用了,而我们想在 esm 里用 import,其他情况才用全局类型。

有啥方式能约束在 esm 里只能 import 用,但是其他地方可以做为全局类型呢?

TypeScript 专门为这种情况设计个了语法,叫 export as namespace xxx;

比如上面的代码可以这样写:

export = Guang;
export as namespace Guang;

declare namespace Guang {
    export const name = 'guang';
    export const age = '20';
}

export = Guang 是兼容老的 ts import 语法的,支持 umd 得加上这一行,然后加上 export as namespace Guang;

这样你在非 esm 里就可以通过全局类型的方式使用它了:

UMD 的包如何导出 TS 类型

而在 esm 里,如果也是这样用的,它会报错

UMD 的包如何导出 TS 类型

说是你在 esm 模块里用了一个 UMD 的 global 类型,建议用 import 的方式代替。

如果你用 import 的方式引入了这个类型,就不报错了:

UMD 的包如何导出 TS 类型
image.png

这就是它比 declare global 好的地方,可以约束在 esm 里用 import 引入,非 es module 可以作为全局类型。

这样就完美兼容了 esm 和 umd 两种模块引入方式。

而且如果你不想要这种限制,也可以在 tsconfig.json 里关掉。

有个 allowUmdGlobalAccess 的编译选项就是控制是否支持在 es module 里使用 UMD 全局类型的:

UMD 的包如何导出 TS 类型

默认是 false,开启以后在 es module 里使用 UMD 全局类型就不报错了:

UMD 的包如何导出 TS 类型

很多库都需要兼容 esm 和 umd 的使用方式都会这样用,比如 react:

UMD 的包如何导出 TS 类型

所以,如果你开发的库需要支持 esm 和 umd 的话,可以用 export namespace as xxx 来导出,会比 declare global 更好。

总结

现在 TypeScript 的模块都是 es module 的方式引入的,但有一些包是支持 umd 的,它们可能用各种方式引入模块,为了实现 umd 模块的类型检查,可以用 declare global 把导出的变量变为全局的。

但是在 es module 里还是希望使用 import 引入,非 es module 才用全局类型,所以更好的方式是使用 export as namespace xxx。

用这种方式声明的类型,当在非 esm 中使用时,会作为全局类型,而在 esm 中如果直接引用全局类型会报错,建议用 import 引入。这是它比 declare global 更好的地方。

当然,也可以把 allowUmdGlobalAccess 的编译选项设置为 true 来放开这种约束。

像 react 这种支持 umd 的库都是用这种方式导出类型的,如果你也要开发一个支持 umd 的库,不妨也试试 export as namespace 吧。

原文始发于微信公众号(神光的编程秘籍):UMD 的包如何导出 TS 类型

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/109272.html

(0)
神光的编程秘籍的头像神光的编程秘籍

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!