✅创作者:陈书予
🎉个人主页:陈书予的个人主页
🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区
🌟专栏地址: 三十天精通 Vue 3
文章目录
- 引言
- 一、为什么使用TypeScript?
- 二、Vue 3和TypeScript的基础
- 2.1 安装TypeScript
- 2.2 配置TypeScript
- 2.3 Vue 3中使用TypeScript
- 三、Vue 3和TypeScript的进阶
- 3.1 类型检查
- 3.2 接口
- 3.3 枚举
- 3.4 泛型
- 3.5 装饰器
- 3.6 Mixins
- 四、Vue 3和TypeScript的最佳实践
- 4.1 单文件组件
- 4.2 组件通信
- 4.3 组件 Props
- 4.4 事件处理
- 4.5 生命周期
- 4.6 Vuex和TypeScript
- 4.7 Axios和TypeScript
引言
Vue.js 3.x是一种流行的JavaScript框架,它允许我们使用模板语法来快速开发应用程序、组件化和封装,同时还提供了高效的响应式数据绑定、组件通信等众多特性。相对于其前身Vue.js 2.x,Vue 3.x进一步增强了TypeScript的支持,使我们可以更容易地将TypeScript与Vue.js结合使用,以提高我们的代码质量、可维护性和开发效率。
本篇文章将从为什么使用TypeScript、TypeScript的优势、Vue 3和TypeScript的基础、Vue 3和TypeScript的进阶、以及Vue 3和TypeScript的最佳实践等几个方面介绍如何使用Vue 3和TypeScript进行开发。
一、为什么使用TypeScript?
TypeScript相比于JavaScript,有如下的优点:
1.静态类型检查:使用静态类型检查可以帮助我们在编码时发现一些隐藏的类型错误,从而在开发周期的早期就能够进行修改,避免在其他环节引入更严重的bug。
2.代码提示:使用TypeScript,开发者在写代码的时候会得到更全面、更准确的代码提示,这对开发效率和代码编写的准确性都有积极的影响。
3.代码可读性提高:使用TypeScript可以明确地表达代码中的数据类型、接口和方法的类型等信息,这能够提高代码的可读性。
4.文档自动生成:TypeScript可以根据代码生成文档,更加方便地为其他的开发者提供使用帮助。
5.维护成本降低:代码中的类型和接口可以帮助开发团队理解整个代码库,降低了维护代码的成本。
二、Vue 3和TypeScript的基础
在开始使用Vue.js 3和TypeScript编写代码之前,需要先安装TypeScript,配置TypeScript环境。
2.1 安装TypeScript
TypeScript的安装比较简单,可以使用npm工具进行安装。执行以下命令即可完成TypeScript的安装:
npm install -g typescript
2.2 配置TypeScript
在安装了TypeScript之后,我们需要进行一些简单的TypeScript配置,以便在开发Vue 3应用程序时使用。
TypeScript的配置文件为tsconfig.json
,我们需要在Vue 3项目的根目录下添加一个tsconfig.json
文件。例如,在默认的Vue 3项目文件夹中,该文件的路径为./tsconfig.json
。我们可以通过以下的命令来创建tsconfig.json
文件:
tsc --init
这个命令将生成一个包含默认设置的tsconfig.json
文件。我们可以针对具体的项目,根据需要进行一些简单的编辑,比如指定目标JavaScript版本、配置编译选项等等。
2.3 Vue 3中使用TypeScript
默认情况下,Vue 3项目使用单文件组件(SFC)来管理其组件,而这些组件可以通过业务逻辑脚本文件中的JavaScript代码来实现。如果我们要使用TypeScript编写业务逻辑,就需要将.js
文件转换为.ts
文件。
我们可以在.vue
文件中使用TypeScript,只需要在<script>
标记中添加lang="ts"
属性即可。下面是一个示例:
<template>
<div>
{{ message }}
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'HelloWorld',
props: {
message: String
},
setup(props) {
return {
message: props.message
};
}
});
</script>
在这个例子中,我们可以看到<script>
标记中的lang
属性设置为"ts"
,这是告诉Vue 3,SFC文件中的脚本代码使用TypeScript编写。
三、Vue 3和TypeScript的进阶
3.1 类型检查
TypeScript最重要的一个特性就是类型检查,它可以帮助我们在代码编写过程中避免许多潜在的类型错误。在Vue 3中,我们也可以使用类型检查来增加代码的可维护性和健壮性。
下面是一个使用类型检查的示例:
import { defineComponent, PropType } from 'vue';
interface User {
name: string;
age: number;
address: string;
}
export default defineComponent({
name: 'UserCard',
props: {
user: {
type: Object as PropType<User>,
required: true
}
},
setup(props) {
const { user } = props;
const isValid = (data: User): boolean => {
return (data && data.name && data.age && data.address);
};
return {
user: isValid(user) ? user : null
};
}
});
在这个示例中,我们使用了一个名为User
的接口表示一个User
对象,该对象包含name
、age
和address
三个属性。由于props中的user
是一个Object
类型的值,我们需要使用PropType
将其类型限定为User
。
在setup()
函数中,我们定义了一个名为isValid()
的函数,用于检查传入的user
对象是否合法,如果合法则返回该对象,否则返回null
。这个函数会在组件的user
属性被初始化时被调用,在组件的其它位置,也可以使用isValid()
函数对任意User
对象进行检查。
3.2 接口
TypeScript中的接口可以用来描述一个对象的形状(也就是属性、方法的集合),从而可以在多个地方进行类型检查。Vue 3中组件的props和emit选项可以使用接口来描述其类型。
下面是一个示例:
import { defineComponent } from 'vue';
interface Props {
message: string;
}
interface Emit {
change: (value: string) => void;
}
export default defineComponent({
name: 'HelloWorld',
props: {
message: {
type: String,
required: true
}
},
emits: ['change'],
setup(props, { emit }) {
const handleChange = (event: Event) => {
const value = event.target.value;
emit('change', value);
};
return {
handleChange
};
}
});
在这个示例中,我们定义了一个名为Props
的接口,用于描述HelloWorld
组件的props对象的形状,该对象包括一个名为message
的字符串属性。
我们还定义了一个名为Emit
的接口,用于描述HelloWorld
组件的emit对象的形状,该对象包括一个名为change
的事件。
在组件中,我们使用了Props
接口来描述组件中的message
属性,使用了Emit
接口来描述组件的emit对象。我们还在组件中定义了一个名为handleChange()
的函数,用于将输入框中的值传递给父组件,该函数会在输入框的值发生变化时被调用,并触发change
事件。
3.3 枚举
TypeScript中的枚举可以方便地为一组相关的常量赋予一组有意义的名字,从而增加代码的可读性。Vue 3中也可以使用枚举来描述一些基于数字或字符串的常量。
下面是一个枚举的示例:
import { defineComponent } from 'vue';
enum OrderStatus {
Unpaid = 'unpaid',
Paid = 'paid',
Shipped = 'shipped',
Delivered = 'delivered'
}
export default defineComponent({
name: 'OrderList',
setup() {
const orderStatusToString = (status: OrderStatus) => {
switch (status) {
case OrderStatus.Unpaid:
return '待付款';
case OrderStatus.Paid:
return '已付款';
case OrderStatus.Shipped:
return '已发货';
case OrderStatus.Delivered:
return '已签收';
}
};
return {
orderStatusToString
};
}
});
在这个示例中,我们定义了一个名为OrderStatus
的枚举,用于描述订单状态的四个值。我们还定义了一个名为orderStatusToString()
的函数,用于将枚举值转换为相应的中文订单状态名称。
在组件的setup()
函数中,我们通过return
语句将orderStatusToString()
函数暴露给模板。
3.4 泛型
TypeScript中的泛型可以方便地为函数或类中的类型参数添加类型约束,从而提供更加灵活和安全的泛型编程能力。Vue 3中的组件props和emit属性也可以使用泛型来描述其类型。
下面是一个示例:
import { defineComponent, PropType } from 'vue';
interface User<T> {
id: number;
name: string;
age: number;
data: T;
}
export default defineComponent({
name: 'UserCard',
props: {
user: {
type: Object as PropType<User<string>>,
required: true
}
},
setup(props) {
const { user } = props;
return {
userName: user.name,
userData: user.data
};
}
});
在这个示例中,我们定义了一个名为User
的泛型接口,其中类型参数T
表示data
属性的类型。
在组件的props中,我们使用了PropType
来将user
属性限定为一个泛型类型为string
的User
对象。
在setup()
函数中,我们从user
属性对象中取出了它的name
和data
属性,并将它们暴露给模板。
3.5 装饰器
TypeScript中的装饰器是一种特殊的语法,可以用来修饰类、方法、属性和参数等,从而添加额外功能和约束。Vue 3支持使用装饰器来修饰组件、属性和方法等。常用的装饰器包括@Component
、@Prop
、@Emit
、@Watch
等。
下面是一个示例:
import { defineComponent } from 'vue';
@Component
export default class HelloWorld extends Vue {
@Prop({ type: String, required: true })
message!: string;
@Emit()
handleClick() {
console.log('click');
}
@Watch('message')
handleWatch(newVal: string, oldVal: string) {
console.log(`message has been changed from ${oldVal} to ${newVal}`);
}
};
在这个示例中,我们使用了三个常用的装饰器:
@Component
:用于修饰Vue 3组件类,将类声明为一个Vue组件。@Prop
:用于修饰类中的属性,将属性声明为Vue组件的prop属性。@Emit
:用于修饰类中的方法,将方法标记为发射的自定义事件。@Watch
:用于修饰类中的方法,将方法标记为监视的数据变化。
3.6 Mixins
Mixins是一种复用组件逻辑的方式,Vue 3中的Mixins与TypeScript结合使用时需要注意,因为Mixins扩展的属性和方法类型不能添加到子类原有的类型定义中。为了解决这个问题,可以使用交叉类型或者泛型约束。
下面是一个示例:
import { defineComponent } from 'vue';
interface Mixin {
message: string;
showMessage(): void;
}
const MyMixin = {
data() {
return {
message: 'Hello Mixin!'
};
},
methods: {
showMessage() {
console.log(this.message);
}
}
};
export default defineComponent({
name: 'HelloWorld',
mixins: [MyMixin as Mixin],
setup() {
const handleClick = () => {
this.showMessage();
};
return {
handleClick
};
}
});
在这个示例中,我们定义了一个名为Mixin
的接口,用于描述Vue 3 Mixin中的属性和方法。我们还定义了一个名为MyMixin
的Mixins对象,该对象包含一个data
对象和methods
对象。
在组件中,我们通过将MyMixin
对象强制转换为Mixin
接口类型并传给mixins
选项,使组件可以复用MyMixin
中的属性和方法。
最后,我们定义了一个名为handleClick()
的函数,该函数会调用showMessage()
方法。
四、Vue 3和TypeScript的最佳实践
4.1 单文件组件
在Vue 3和TypeScript中使用单文件组件时,建议在.vue文件中使用
同时,需要注意的是,如果要让Vue 3识别TypeScript文件,需要在项目中安装vue-tsc并且在tsconfig.json中正确配置:
{
"compilerOptions": {
...
"module": "esnext",
"target": "esnext",
"jsx": "preserve",
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node",
"types": [
"webpack-env",
"@types/node",
"@vue/cli-plugin-typescript"
],
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noImplicitAny": false
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": [
"node_modules"
]
}
4.2 组件通信
在Vue 3和TypeScript中,组件之间的通信可以使用props和event进行。
props可以定义组件之间所需的属性,并且可以在组件内部进行类型检查。例如:
interface Props {
message: string
}
export default defineComponent<Props>({
props: {
message: {
type: String,
required: true,
},
},
...
})
event可以定义组件之间所需的事件类型,并且可以在组件内部进行类型检查。例如:
interface CustomEvents {
click: () => void;
}
export default defineComponent<{}, CustomEvents>({
emits: ["click"],
...
})
4.3 组件 Props
在Vue 3和TypeScript中,组件的props可以在组件内部进行类型检查,这可以更好地保证组件的健壮性。
例如,在组件定义时,可以使用Props interface定义prop的类型,并在props选项中进行声明。如下所示:
interface Props {
message: string
}
export default defineComponent<{}, {}, Props>({
props: {
message: {
type: String,
required: true,
},
},
...
})
4.4 事件处理
在Vue 3和TypeScript中,事件处理的方式与JavaScript中相同,不需要进行特殊处理。不过为了确保正确性和代码的健壮性,建议定义事件的类型,并在组件的emits选项中进行声明。
例如:
interface CustomEvents {
click: () => void;
}
export default defineComponent<{}, CustomEvents>({
emits: ["click"],
...
})
4.5 生命周期
在Vue 3和TypeScript中,生命周期钩子仍然有效,但是需要在组件类型定义时,将使用到的生命周期钩子也进行声明。
例如:
export default defineComponent<{}, {}, {}, {}, {
mounted: () => void;
updated: () => void;
}>({
mounted() {
console.log("Mounted!");
},
updated() {
console.log("Updated!");
},
...
})
4.6 Vuex和TypeScript
在使用Vuex和TypeScript时,需要定义store中的state、mutations和actions等类型,并在组件中使用mapState、mapMutations和mapActions等工具来连接store。
例如,定义store中的state类型:
interface State {
count: number
}
const store = createStore<State>({
state: {
count: 0,
},
...
})
在组件中使用mapState连接store:
import { mapState } from "vuex";
import { State } from "@/store";
export default defineComponent({
computed: {
...mapState<State, "count">(["count"]),
},
...
})
4.7 Axios和TypeScript
在Vue 3和TypeScript中使用axios,需要安装axios和@types/axios库,并在组件中定义返回类型,并在代码中使用async/await或者Promise等方式来处理异步操作。
例如,在组件中定义一个API请求方法:
import axios, { AxiosResponse } from "axios";
interface ResponseData {
data: string;
}
async function fetchData(): Promise<AxiosResponse<ResponseData>> {
return await axios.get("/api/data");
}
在组件中使用async/await调用API请求:
export default defineComponent({
async mounted() {
const response = await fetchData();
console.log(response.data);
},
...
})