Typescript 支持
什么是TypeScript
TypeScript
是JavaScript
的强类型版本,就然后在编译期去掉类型和特有语法,生成纯粹的JavaScript
代码。由于最终在浏览器中运行的仍然是JavaScript
,所以TypeScript
并不依赖于浏览器的支持,也并不会带来兼容性问题。
TypeScript
是JavaScript
的超集,这意味着他支持所有的JavaScript
语法。并在此之上对JavaScript
添加了一些扩展,如 class / interface / module 等。这样会大大提升代码的可阅读性。
TypeScript优势
静态类型检查
静态类型检查可以避免很多不必要类型的错误,不用在调试的时候才发现问题。
IDE 智能提示 在
TypeScript
这一类语言之前,JavaScript
的智能提示基本完全依赖 IDE 提供的猜测。局限性就是,这种猜测可能并不正确。并且也缺乏更多的辅助信息, 所以要正确使用一个类库, 得不断地在文档和 IDE 之间切换,影响心情和效率, 而TypeScript
不仅自己写的类库有丰富的类型信息。代码重构
有时候的确需要修改一些变量/属性/方法名,牵涉到属性和方法的时候,很多改动是跨文件的,不像普通变量可以简单定位 scope , 属性方法名的重命名对于
JavaScript
来说异常痛苦, 一方面是修改本身就不方便, 另一方面是改了还不确定该改的是不是改了,不该改的是不是也改了。而TypeScript
的静态类型系统就可以较为完美的解决这个问题。可读性
对于阅读代码的人来讲,各种便利的类型一目了然,更容易明白作者的意图。
使用方式
.mpx中编写ts
.mpx文件中 script 标签声明 lang 为 ts ,在编译时会自动这部分 script 中的内容进行ts 类型检查
<script lang="ts">
// 内联编写ts代码
</script>
由于大部分 IDE 对 ts 的语法提示支持都只对 .ts 和 .d.ts 文件生效,上述在 .mpx 文件中编写ts代码虽然能在编译时进行 ts 类型检查,但是无法享受 IDE 中编写 ts 时的代码提示和实时报错等优秀体验,所以,我们更建议大家创建一个 .ts 文件进行 ts 代码编写,通过 src 的方式引入到 .mpx 当中
<script lang="ts" src="./index.ts"></script>
为.ts文件添加loader
在 Webpack 配置中添加如下 rules 以配置 ts-loader
{
test: /\.ts$/,
use: [
'babel-loader',
'ts-loader'
]
}
编写tsconfig.json文件
对相关配置不熟悉的同学可以直接采用下面配置,能够最大限度发挥 Mpx 中强大的 ts 类型推导能力
{
"compilerOptions": {
"target": "es6",
"allowJs": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"moduleResolution": "node",
"lib": [
"dom",
"es6",
"dom.iterable"
]
}
}
增强类型
如果需要增加 Mpx 的属性和选项,可以自定义声明 TypeScript 补充现有的类型。
例如,首先创建一个 types.d.ts 文件
// types.d.ts
import { Mpx } from '@mpxjs/core'
declare module '@mpxjs/core' {
// 声明为 Mpx 补充的属性
interface Mpx {
$myProperty: string
}
}
之后在任意文件只需引用一次 types.d.ts 声明文件即可,例如在 app.mpx 中引用
// app.mpx
/// <reference path="./types.d.ts" />
import mpx from '@mpxjs/core'
mpx.$myProperty = 'my-property'
类型推导及注意事项
Mpx 基于泛型函数提供了非常方便用户使用的反向类型推导能力,简单来说,就是用户可以用非常接近于 js 的方式调用 Mpx 提供的 api ,就能够获得大量基于用户输入参数反向推导得到的类型提示及检查。但是由于 ts 本身的能力限制,我们在 Mpx 的运行时中添加了少量辅助函数和变种api,便于用户最大程度地享受反向类型推导带来的便利性,具体的注意事项和使用方法如下述例子
import {createComponent, getComputed, getMixin, createStoreWithThis} from '@mpxjs/core'
// createStoreWithThis作为createStore的变种方法,主要变化在于定义getters,mutations和actions时,
// 获取自身的state,getters等属性不再通过参数传入,而是通过this.state或者this.getters等属性进行访问,
// 由于TS的能力限制,getters/mutations/actions只有使用对象字面量的方式直接传入createStoreWithThis时
// 才能正确推导出this的类型,当需要将getters/mutations/actions拆解为对象编写时,
// 需要用户显式地声明this类型,无法直接推导得出。
const store = createStoreWithThis({
state: {
aa: 1,
bb: 2
},
getters: {
cc() {
return this.state.aa + this.state.bb
}
},
actions: {
doSth3() {
console.log(this.getters.cc)
return false
}
}
})
createComponent({
data: {
a: 1,
b: '2'
},
computed: {
c() {
return this.b
},
d() {
// 在computed中访问当前computed对象中的其他计算属性时,需要用getComputed辅助函数包裹,
// 而除此以外的任何场景下都不需要使用,例如访问data或者mixins中定义的computed等数据
return getComputed(this.c) + this.a + this.aaa
},
// 从store上map过来的计算属性或者方法同样能够被推导到this中
...store.mapState(['aa'])
},
mixins: [
// 使用mixins,需要对每一个mixin子项进行getMixin辅助函数包裹,支持嵌套mixin
getMixin({
computed: {
aaa() {
return 123
}
},
methods: {
doSth() {
console.log(this.aaa)
return false
}
}
})
],
methods: {
doSth2() {
this.a++
console.log(this.d)
console.log(this.aa)
this.doSth3()
},
...store.mapActions(['doSth3'])
}
})
更加具体的使用方法和实现原理我们会在后面的文档和文章中补充完整