老实说我对
ts
写业务一直不太感冒,总感受影响效率。但事有两面,好比之前写angular
,被谷歌强迫一下,写一段时间以后感受也不赖,有时还有一种莫名的优越感,ts+rxjs+decorator
各类高大上,咱ng
就是nb。像不像小媳妇儿嫁给第一次见面的小少爷,过着过着以为还挺滋润,成天跑出去炫耀~javascript
小伙伴们管我要
vue3+ts
项目好久了,我就纳闷了,写个vue3
,为啥非要用ts
哪?他们说ts
写多有牌面呀,面试提及来都以为高人一截。这说明一个卷的现状,如今前端JD
里面愈来愈多提到ts
要求,这让应聘者以为ts
是个加分项,因此就不得不学会。html
文本主要结合案例体验一下vue3+ts
开发的实际效果。到底适不适合你和你的项目,还得根据各位看官本身掌握程度和项目实际状况综合判断。 本文主要涉及如下知识点:前端
ts
能为咱们带来什么ts+vue3
的两种姿式ts
编写vue组件的两种姿式
setup
方式ts
编写vuex
的两种姿式
$store
方式setup
方式查看本文配套视频教程vue
如下结论来自官方团队视频教程:java
固然也有负面影响:react
下面咱们就整合ts到vue3中,主要有如下两种环境:面试
新建立项目:vuex
vue create my-project
复制代码
已存在项目:typescript
vue add typescript
复制代码
新建立项目:npm
npm init @vitejs/app
复制代码
已存在项目,本身手撸~
编写一个组件常见任务:
data
类型定义props
类型定义methods
和computed
类型支持composition api
中的类型支持使用<script lang="ts">
和 defineComponent
定义一个组件。
<template>
<div>{{ counter }}</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
data() {
return {
counter: 0
}
},
});
</script>
复制代码
工具支持:Volar
data中的对象类型利用类型断言肯定数据类型。
首先定义一个类型,types.d.ts:
export type Todo = {
id: number;
name: string;
completed: boolean;
}
复制代码
定义一个组件Comp.vue,并引入这个类型:
<script lang="ts"> import type { Todo } from "../types"; export default defineComponent({ data() { return { // 利用类型断言 items: [] as Todo[] } }, created() { // 此处会得到类型支持 this.items.push({ id: 1, name: 'vue3', completed: false }) } }); </script>
复制代码
模板定义
<template>
<!-- 此处会得到类型支持 -->
<div v-for="item in items" :key="item.id" class="todo-item">
{{ item.name }}
</div>
</template>
复制代码
props
中的对象类型利用类型断言和PropType<T>
export type TitleInfo = {
value: string;
color: string;
}
复制代码
<script lang="ts"> // 属性类型须要PropType支持 import { PropType } from "vue"; import type { TitleInfo } from "../types" export default defineComponent({ props: { // 利用泛型类型约束对象类型 titleInfo: Object as PropType<TitleInfo>, }, }) </script>
复制代码
模板中使用
<h1 :style="{ backgroundColor: titleInfo?.color }">{{ titleInfo?.value }}</h1>
复制代码
<Comp :title-info="{ value: '待办事项', color: '#41b883' }"></Comp>
复制代码
computed要着重标识函数返回类型。
computed: {
doubleCounter(): number {
return this.counter * 2
}
},
复制代码
标识函数形参和返回类型便可。
methods: {
newTodo(todoName: string): Todo {
return {
id: this.items.length + 1,
name: todoName,
completed: false,
};
},
addTodo(todo: Todo) {
this.items.push(todo);
this.todoName = ''
},
},
复制代码
setup script方式编写代码会更加简洁。 下面范例代码目标是不改变template结构,重构script部分,以composition api方式实现,咱们来看看有什么变化:
单值利用泛型方法ref<T>()
定义
<script setup lang="ts"> import { defineProps, ref, computed } from "vue"; import type { Todo } from "../types" const items = ref<Todo[]>([]); items.value.push({ id: 1, name: "vue3", completed: false, }); </script>
复制代码
利用defineProps()定义属性,经常使用手法有两种:
defineProps<{ titleInfo: TitleInfo }>()
defineProps({ titleInfo: Object as PropType<TitleInfo> })
使用computed()定义,一般类型能够推断出来。
const counter = ref(0);
const doubleCounter = computed(() => counter.value * 2);
复制代码
就是普通函数,定义形参类型和返回值类型便可。
const todoName = ref("");
function newTodo(todoName: string): Todo {
return {
id: items.value.length + 1,
name: todoName,
completed: false,
};
}
function addTodo(todo: Todo) {
items.value.push(todo);
todoName.value = "";
}
复制代码
vuex总体对ts的支持比较蹩脚,这是之前架构问题引发的,咱们一块儿来感觉一下:
建立store实例,store/index.ts
import { createStore, Store } from "vuex";
import { State } from "./vuex";
const store = createStore({
state: {
counter: 0,
},
});
export default store;
复制代码
引入vue,main.ts
createApp(App).use(store).mount("#app");
复制代码
使用,Comp.vue
import { mapState } from "vuex";
export default defineComponent({
computed: {
// 映射state counter
...mapState(['counter']),
doubleCounter(): number {
// $store已经有类型了
return this.$store.state.counter * 2;
},
},
}
复制代码
咱们但愿this.$store
是有明确类型的, 这须要为组件选项添加一个明确类型的$store
属性,能够为ComponentCustomProperties
扩展$store
属性,store/vuex.d.ts
import { ComponentCustomProperties } from "vue";
import { Store } from "vuex";
// declare your own store states
export interface State {
counter: number;
}
declare module "@vue/runtime-core" {
// provide typings for `this.$store`
interface ComponentCustomProperties {
$store: Store<State>;
}
}
复制代码
setup
中使用useStore
时要类型化,共须要三步:
InjectionKey
InjectionKey
InjectionKey
给 useStore
定义一个InjectionKey
,约束Store
中State
类型,store/index.ts
import { InjectionKey } from "vue";
import { State } from "./vuex";
// define injection key
export const key: InjectionKey<Store<State>> = Symbol();
复制代码
main.ts中做为参数2传入vuex插件
import { key } from "./store";
// 做为参数2传入key
createApp(App).use(store, key).mount("#app");
复制代码
使用时,store就能够有明确类型了,CompSetup.vue
import { useStore } from 'vuex'
import { key } from '../store'
const store = useStore()
const counter = computed(() => store.state.counter);
复制代码
封装useStore,避免每次导入key,store/index.ts
import { useStore as baseUseStore } from "vuex";
export function useStore() {
return baseUseStore(key);
}
复制代码
使用变化,CompSetup.vue
import { useStore } from '../store'
const store = useStore()
复制代码
建立模块文件,store/modules/todo.ts
import { Module } from "vuex";
import { State } from "../vuex";
import type { Todo } from "../../types";
const initialState = {
items: [] as Todo[],
};
export type TodoState = typeof initialState;
export default {
namespaced: true,
state: initialState,
mutations: {
initTodo(state, payload: Todo[]) {
state.items = payload;
},
addTodo(state, payload: Todo) {
state.items.push(payload)
}
},
actions: {
initTodo({ commit }) {
setTimeout(() => {
commit("initTodo", [
{
id: 1,
name: "vue3",
completed: false,
},
]);
}, 1000);
}
},
} as Module<TodoState, State>;
复制代码
引入子模块,store/index.ts
import todo from "./modules/todo";
const store = createStore({
modules: {
todo,
},
});
复制代码
状态中添加模块信息,vuex.d.ts
import type { TodoState } from "./modules/todo";
export interface State {
todo?: TodoState;
}
复制代码
组件中使用,Comp.vue
export default {
data() {
return {
// items: [] as Todo[],
};
},
computed: {
items(): Todo[] {
return this.$store.state.todo!.items
}
},
methods: {
addTodo(todo: Todo) {
// this.items.push(todo);
this.$store.commit("todo/addTodo", todo);
this.todoName = "";
},
},
}
复制代码
setup中使用,CompSetup.vue
const items = computed(() => store.state.todo!.items)
store.dispatch('todo/initTodo')
function addTodo(todo: Todo) {
// items.value.push(todo);
store.commit('todo/addTodo', todo)
todoName.value = "";
}
复制代码
vue3+ts
体验中规中矩,跟react
相比还有差距,尤为vuex
这块支持比较弱,仅能作到state
类型支持,getters
依然any
,子模块mutations
和actions
更是彻底抓瞎,这个是之前架构问题,估计之后会有vuex5
来解决。
ts显然仍是作开源库和框架更好一点,业务编写不是特别必要。
微信搜索并关注“村长学前端”,回复“ts+vue3”得到文中完整代码
感谢你们观看,我是村长,一个热爱分享的程序猿。若是以为本文还不错,记得点赞+收藏哦,说不定哪天就用得上!