最近在升级项目,用到了TypeScript
,简单总结一下JS
转TS
,尤其是在vue
中的使用方式。
基础语法
对于TS
的基础语法,这里就不多介绍了,看官网即可,毕竟巨硬的文档可以秒杀一众系列丛书。
放个链接:
- TypeScript文档
-
上面是英文官方的,保持了最新。下面好像也是官方的,但是不是最新,不过没关系,大体都差不多的。
编写 ts 文件
TypeScript文件以.ts
结尾,在内容书写上基本按照 JavaScript 格式即可,需要注意有些地方需要显式的给出类型声明,比如:
function(id: number) {
// do something...
}
另外 ts
还扩展了 js
的很多功能,比如可以自定义一个 type
:
type T = "a" | "b";
let a: T = "a"; // a 只能等于 "a" or "b"
这就可以控制输入指定字符,不必再担心 js
里面那种等于一个字符串,但是输入错误从而导致的bug等等。
更多的细节可以参照文档。
js 文件转 ts 文件
1、可以直接修改文件
这种方式很暴力,适合小文件,你非常确定可以用很短的时间就能搞定的,比如一个很小的工具函数。只需要添加一些类型声明,返回值声明,或者命名空间即可。
这是最简单的一种方式,也非常硬核,但是有一个缺点,对于已经写好的大文件来说,比如叫你修改 jquery
源码,这是十分困难的,所以就有了下面的方式。
2、对 js 文件进行声明
这种方式不需要对 js 源码进行修改,只是在同级文件夹下或者在你的 tsconfig.json
中配置好的 types
文件夹路径下创建一个 同名的.d.ts
文件即可。
.d.ts
文件是TypeScript
针对JavaScript
的声明文件,就是用于声明 js 文件。你可以手动编写一个对应的声明文件。
手动编写一个声明文件
具体编写方式,可以参看 TypeScript的声明文件。
如果是这样,直接贴链接就好了嘛。
有兴趣可以先看看什么是声明文件。但是我要说的是,使用工具生成的声明文件远比自己写要快的多,既然有工具,为什么不用呢。
使用工具生成声明文件
首先,你需要配置 tsconfig.json
。在你的项目根目录中,找到该文件,并填写如下信息:
{
// 更改此选项以匹配您的项目
"include": ["src/**/*"],
"compilerOptions": {
// 告诉TypeScript读取JS文件,因为通常它们作为源文件被忽略
"allowJs": true,
// 生成 .d.ts 文件
"declaration": true,
// 这个编译器运行时应该只输出d.ts文件
"emitDeclarationOnly": true,
// 类型声明应该放在这个目录中。删除该选项,.d.ts 文件将与 js 文件同级放置
"outDir": "dist",
},
}
然后执行:
npx typescript your/js/file/path.js --declaration --allowJs --emitDeclarationOnly --outDir types
- 请替换命令行中的路径信息。
比如我需要给项目中的 src/utils/colors.js
文件创建一个声明文件,则输入这个文件路径,然后执行,稍等之后,就可以看到已经编译成功!
然后再项目中就可以看到新创建的声明文件了。
js 的源文件:
新创建的声明文件:
并不需要其他操作,这样直接就可以在项目中引入了。当然,你还可以对声明文件进行小规模修改,比如这里的参数类型,我只想要一个字符串,就可以把 any
改为 string
即可。
在 vue 文件中使用 ts
有了上面的转换方式,就可以灵活的使用 js 转 ts 的方式,那么在 vue 文件中,如果操作呢?
这里有两种方式,但是他们都需要一个前置操作:
将 vue 文件的 <script>
标签中的 lang
属性修改为 ts
,即:
<script lang="ts">
// vue
</script>
使用 class 方式
直接上代码,因为与平时写的 vue 文件基本不一样。
import { Vue, Component } from "vue-property-decorator";
@Component({SomeOtherComponent})
export default class VueClassComponent extends Vue {
// 等效于一个 data 的属性
private dataA: number = 1;
// 等效于一个 computed 属性
get computedA: string {
return this.dataA === 1 ? "a" : "b";
}
// 等效于一个 method 方法
private onClick(e: MouseEvent): void {
return true;
}
// 声明周期函数
private created() {
// do something
}
private beforeDestroy() {
// do something
}
}
基本就是这样的,vue 的官方也是以这样为主作为描述的,但是这样的方式,目测并不能更好的兼容 vue3,毕竟 vue3 的最大的写法变化并不是使用这样的方式,而是在原有基础上添加了一个机动性极强的 setup()
方法,所以我在修改之出就排除了这样的使用方式。
使用更像 vue 的原有方式
vue 的灵活之处可能就在这里,书写上的灵活多变,非常适合快速将 js 升级到 ts。
只需要在原有 vue 文件中,稍作修改:
import Vue, { PropType } from "vue";
export default Vue.extend({
name: "VueComponent",
props: {
someProps: {
type: String,
default: ""
},
// 因为传值只能使用 js 的基本类型,但是 vue 提供了转换方法。
// 在 ts 中,类型应当是 interface 的
someComplexProps: {
type: Object as PropType<MyComplexObject>
}
},
data() {
return {
dataA: 1, // 不需要给出类型,默认就是 number
dataB: void 0 as undefined | number // 既可以是单一类型,可以是复合类型
}
},
computed: {
// 这里需要注意,计算属性都应当显式的给出返回类型。这点在 vue 的文档中也有说明,因为动态无法映射出对应的类型,需要显式的声明一下。
computedA(): number {
return 1;
}
},
methods: {
onClick(e: MouseEvent) {
// do something
}
}
// 其它内容都是一样的
});
使用这样的方式,不管是大体逻辑还是修改代码,都是基本保持一致的,这样的方式简直了~
给 vue 原型注入自定义属性
有时候我们需要全局使用一些自定义的方法、属性等,在 js 时代,直接在 main
文件中直接在 vue 的原型链中添加。而使用 ts,不仅要添加到原型链,还需要在声明文件中声明一下下。
比如,我想给 vue 添加一个名为 $u
的工具方法,需要分三步:
1、导出工具方法,并声明:
工具函数在 src/utils
文件夹中,创建一个 index.ts
,并将所有工具函数整理成如下:
// 是否函数
const isFunction = (o: any) => {
return Object.prototype.toString.call(o).slice(8, -1) === "Function";
};
// 是否布尔
const isBoolean = (o: any) => {
return Object.prototype.toString.call(o).slice(8, -1) === "Boolean";
};
// 导出函数实体
export const utils = {
isFunction,
isBoolean
}
// 导出函数声明
export interface Utils {
isFunction: (o: any) => boolean,
isBoolean: (o: any) => boolean
}
2、添加原型链
在 main.ts
中添加原型链:
import { utils } from "@/utils";
Vue.prototype.$u = utils;
3、添加声明
最后在 /src
目录下找到 vue-prototype.d.ts
文件,导入刚才的 Utils
接口声明,并添加:
import { Utils } from "@/utils";
declare module "vue/types/vue" {
interface Vue {
$u: Utils;
}
}
这样就可以在项目中的任意一个 vue 文件使用 $u
这个方法,并且可以点出提示~
结语
到这里就差不多可以转换完成了,我升级项目主要就是它可以提供类型支持,使得我们在项目中不再为类型发愁,好用很多。
文章评论