码字,杂谈

js 升级 ts 之路,含 vue 升级攻略

最近在升级项目,用到了TypeScript,简单总结一下JSTS,尤其是在vue中的使用方式。

基础语法

对于TS的基础语法,这里就不多介绍了,看官网即可,毕竟巨硬的文档可以秒杀一众系列丛书。

放个链接:

编写 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 升级 ts 之路,含 vue 升级攻略》

然后再项目中就可以看到新创建的声明文件了。

js 的源文件:

《js 升级 ts 之路,含 vue 升级攻略》

新创建的声明文件:

《js 升级 ts 之路,含 vue 升级攻略》

并不需要其他操作,这样直接就可以在项目中引入了。当然,你还可以对声明文件进行小规模修改,比如这里的参数类型,我只想要一个字符串,就可以把 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 这个方法,并且可以点出提示~

《js 升级 ts 之路,含 vue 升级攻略》

结语

到这里就差不多可以转换完成了,我升级项目主要就是它可以提供类型支持,使得我们在项目中不再为类型发愁,好用很多。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注