微信小程序 TypeScript 尝试

自从去年开始在项目里写了一段时间 Javascript 后,感受没有类型检查的语言仍是不太适合我,因此一直想尝试下 TypeScript,然而因为项目庞大,人员协做问题,一时半会没办法切成 TypeScript。正好最近有小程序的需求和小程序去年 11 月开始官方支持了 TypeScript,因此拿来练练手。node

Why TypeScript?

大概是我这半年写的 Swift 比较多,而 Swift 中的静态类型和协议是我很喜欢的特性。正好 TypeScript 为 JavaScript 带来了静态类型接口es6

可选的静态类型

“动态类型一时爽,代码重构火葬场“,对于我这种极度喜欢重(xia)构(gai)代码的人来讲,JavaScript 毫无类型提示,类型全靠命名猜想是极度不友好的。而 TypeScript 加上了灵活的类型系统,不只能够编码期检查,还能加强代码的可读性,并提供了 any 类型进行缓冲。typescript

接口

接口和协议,只是不同的叫法而已,Java、C#、TypeScript 叫 Interface,Swift、Kotlin 叫 Protocol,就是一种规则声明。项目中,和后端接口数据交互,页面传递数据,数据持有,方法代理的地方,有了接口就会更加方便,易重构。TypeScript 的 Interface + JavaScript 简单的对象就让数据构建变得简单又不容易出错。小程序

小程序对 TypeScript 的支持

TypeScript 有一个很重要的东西,就是 d.ts 文件。d.ts 文件其实至关于 C 系语言里面的 .h 头文件,声明了对外暴露的方法和属性。而小程序官方对 TypeScript 的支持,意味着官方会维护小程序自己 API 的 d.ts 文件,也就是 typing 库,这样当 API 发生变更时,就能够即时变动。segmentfault

使用也很简单,更新微信开发者工具到最新版,在建立新项目时选择 TypeScript 模板。后端

屏幕快照 2019-01-30 下午8.51.40

建立后,咱们能够看到项目里带上了 typings 库,以及 TypeScript 的配置文件 tsconifg。以后,保存时就不会自动编译了,要点击小程序工具栏的编译按钮才能够。微信

这里有一个坑,笔者电脑安装的 TypeScript 版本是 3.2.2 版本。编译时会被找不到全局类型 CallableFunction 和 NewableFunction。微信开发

image-20190130195121996

解决方法也很简单,到 node_modules 路径下的 TypeScript 包的 bin 目录下,lib.es5.d.ts 文件里面把这两个类型的 Interface 拷贝到,小程序 typing 目录下的 lib.wa.es6.d.ts 里面就能够了。小程序模板里这个文件应该是拷贝 TypeScript 官方的,但没有随着官方升级而改变。工具

事件

视图的事件,对应的类型笔者在 typings 中并无看到有 Interface 定义,因此只能暂时用 any,而后本身再用ui

as 转一下 event 携带的数据的类型。

Page&Data

每一个 Page 对象,在 typing 里是这么定义的。

declare const Page: Page.PageConstructor

interface PageConstructor {
    <D extends IAnyObject, T extends IAnyObject & PageInstance>(
      options: PageInstance<D, T> & T
    ): void
  }
复制代码

也就是说,它支持 D 和 T 两个范型。这两个范型是什么呢?小程序里,Page 是这么写的。

Page({});
复制代码

也就是说,options 参数就是一个 PageInstance,范型也被传入了。

interface PageInstance<D extends IAnyObject = any, T extends IAnyObject = any> extends PageInstanceBaseProps<D>
复制代码

PageInstance 里面定义了 Page 声明周期的方法,并且继承自 PageInstanceBaseProps,并将范型 D 传入。

interface PageInstanceBaseProps<D extends IAnyObject = any> {
    data?: D
    //...
}
复制代码

因此这个 D 范型,其实就是 data 的类型接口。由于 data 不是必须实现的,因此这里是可选型 ?。

那么 T 是什么呢?

T extends IAnyObject & PageInstance
复制代码

T 其实就是对 PageInstance 的拓展,PageInstance 是 Page 的实例接口,那么 T 其实就是在 Page 里面 this 的类型接口了,也就是说,须要在 Page 里新增的方法和属性,都在 T 里定义。

因此,对于一个普通页面咱们能够声明两个接口,一个表明 data, 一个表明 page,举个例子。

interface IIntroPage {
	nextButtonTap(event: any): void;
    isLoading: boolean;
}

interface IIntroData {
    test: string;
}

Page<IIntroData, IIntroPage>({
    isLoading: false,
	nextButtonTap(event: any) {
        this.isLoading = true;
	}
});
复制代码

若是这个页面不须要 data 或者不须要扩展 page,用 IAnyObject 代替 D 或者 T 便可。

interface PageInstanceBaseProps<D extends IAnyObject = any> {
    data?: D
    setData?<K extends keyof D>(
      data: D | Pick<D, K> | IAnyObject,
      callback?: () => void
    ): void
}
复制代码

同时,因为 setData 和 data 都被声明为可选项,使用时须要加上!,this.setData!({})this.data!

其余就没什么了,用上 TypeScript 以后,官方的 API 均可以直接看参数和返回值的类型,不再用去查文档猜想类型了。

调用 JavaScript

为 JavaScript 编写一个简单的 .d.ts 文件,将须要调用的类和方法暴露出来。详情见如何编写一个d.ts文件

最后

虽然笔者用了 TypeScript 不久,但严格的检查的确让我在增删改接口字段能快速全局重构,并且方法调用联想,API 查看也方便了很多。小程序对 TypeScript 的支持平常使用开发是没有什么问题了,就是官方的文档指引比较少。

相关文章
相关标签/搜索