老實說我對
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」得到文中完整代碼
感謝你們觀看,我是村長,一個熱愛分享的程序猿。若是以爲本文還不錯,記得點贊+收藏哦,說不定哪天就用得上!