TypeScript快速上手語法及結(jié)合vue3用法詳解
1、定義原始類型
const a: string = 'foo' const b: number = 100 const c: boolean = true const d: void = undefined const e: null = null const f: undefined = undefined const g: symbol = Symlol()
2、定義object 類型
const foo: object = function () {} // [] // {} const obj: { foo: number,bar: string } = { foo: 123, bar: 'string' }
3.定義數(shù)組類型
// 第一種定義方式,元素類型設(shè)置為 *number* const arr1: Array<number> = [1, 2, 3] // 第二種定義方式,較為常見 const arr2: number[] = [1, 2, 3] // 例子 function sum (...args: number[]) { // 傳統(tǒng)做法是要判斷傳入的參數(shù)是否是數(shù)字, 而TypeScript中只需要像上面這樣對(duì)參數(shù)做一個(gè)類型注解,就行了 return args.reduce(prev, current) => prev + current, 0) } sum(1, 2, 3, 'foo') // 這里傳入了一個(gè)非數(shù)字的值就會(huì)報(bào)錯(cuò)
4.定義元祖類型
const tuple: [number, string] = [18, 'foo'] // const tuple: [number, string] = [18, 18] 類型不匹配,會(huì)報(bào)錯(cuò) // const tuple: [number, string] = [18, 'foo', 'xxx'] 數(shù)量不匹配,會(huì)報(bào)錯(cuò) // 訪問 const age = tuple[0] const name = tuple[1] // 解構(gòu) const [age, name] = tuple
5.定義enum 類型
// enum 對(duì)象的屬性可以不用賦值,默認(rèn)從0開始遞增, 也可以賦值Draft = 5,后面的就從5開始遞增 也可以給具體的值,比如 Draft = 'xxx',這樣后面的屬性都要給具體的值 enum PostStatus { Draft = 0, Unpublished = 1, Published = 2 } const post = { title: 'Hello TypeScript', content: 'TypeScript is a typed superset of JavaScript.', status: PostStatus.Draft // 0 // 1 // 2 }
6.定義函數(shù)類型
// 聲明式函數(shù) // 參數(shù)a和b是number類型,函數(shù)返回是string類型, // 參數(shù)后帶問號(hào)代表是可選參數(shù) // 當(dāng)參數(shù)數(shù)量不固定的時(shí)候可以使用rest運(yùn)算符來接受參數(shù),類型是一個(gè)值為number的數(shù)組 function func1 (a: number, b?: number, ...rest: number[]): string { return 'func1' } // 函數(shù)表達(dá)式定義函數(shù) const func2 = function (a: number, b: number): string { return 'func2' } // 如果把一個(gè)函數(shù)作為參數(shù)傳遞,類似callback函數(shù)。 function fntD(callback: (bl: boolean) => boolean) { callback(true) } function callback(bl: boolean): boolean { console.log(bl) return bl } const dResult = fntD(callback)
7.定義任意類型
// value 可以接受任意類型 function stringfy (value: any) { return JSON.stringify(value) } stringify('string') stringify(10) stringify(true) // foo 可以任意賦值 let foo: any = 'string' foo = 100
8.隱式類型推斷
// age 賦值為 number 類型 let age = 18 // number age = 'string' // 會(huì)警告錯(cuò)誤,因?yàn)閍ge是number類型 let foo // 沒有賦值,就是any類型 foo = 100 foo = 'string'
9.類型斷言
// 假定這個(gè) nums 來自一個(gè)明確的接口 const nums = [110, 120, 119, 112] // 這里TypeScript推斷res的類型為 number|undefined // 因?yàn)樗⒉恢肋@個(gè)i到底在數(shù)組中有沒有 const res = nums.find(i => i > 0) // 這里就會(huì)報(bào)錯(cuò)警告 const square = res * res // 如果我們直接 斷言 這個(gè) res 就是 number 類型 const num1 = res as number // 這里就不會(huì)報(bào)錯(cuò)了 const square = res * res
10、 接口 interface
接口用來約定對(duì)象的結(jié)構(gòu),一個(gè)對(duì)象要實(shí)現(xiàn)一個(gè)接口,就必須擁有這個(gè)接口中所包含的所有成員
interface Post { title: string content: string } function printPost (post: Post) { console.log(post.title) console.log(post.content) } printPost({ title: 'Hello TypeScript', content: 'A JavaScript superset' }) // 特殊的接口成員 可選成員 只讀成員 interface Post{ title: string content: string subtitle?: string // 加問號(hào)就是可選成員 readonly summary: string // 加 readonly 就是只讀成員 } const hello: Post = { title: 'Hello TypeScript', content: 'A javascript superset', summary: 'a javascript' } hello.summary = 'other' // 會(huì)報(bào)錯(cuò),因?yàn)?summary 是只讀成員 // 動(dòng)態(tài)成員 interface Cache { [prop: string]: string } const cache: Cache = {} cache.foo = 'value1' cache.bar = 'value2'
11、類 Class
Class Person { // 在這里賦值,和在構(gòu)造函數(shù)中初始化必須兩者選其一 name: string // = 'init name' 這里可以直接初始化 private age: number // 這里定義 age 為私有屬性 protected gender: boolean // 受保護(hù)的類型 readonly national: string // 只讀屬性,一經(jīng)初始化,不可更改 constructor (name: string, age: number) { // 需要在上面標(biāo)注出構(gòu)造函數(shù)中屬性的類型 this.name = name this.age = age this.gender = true this.national = national } sayHi (msg: string): void { console.log(`I am ${this.name}, ${msg}`) console.log(this.age) } } const tom = new Person('tom', 18) console.log(tom.name) // tom console.log(tom.age) // 報(bào)錯(cuò),因?yàn)?age 是私有屬性,所以訪問不到 console.log(tom.gender) // 報(bào)錯(cuò),因?yàn)?gender 是受保護(hù)的屬性,這里訪問不到 // 在下方新聲明一個(gè)類 student 繼承與 Person class Student extends Person { constructor (name: string, age: number) { super(name, age) console.log(this.gender) // 這里就一個(gè)訪問到 受保護(hù)的屬性 gender }
12.類與接口
interface Eat { eat (food: string): void } interface Run { run (distance: number): void } // Person類,實(shí)現(xiàn)了 Eat 和 Run 兩個(gè)接口 class Person implements Eat, Run { eat (food: string): void { console.log(`優(yōu)雅的進(jìn)餐:${food}`) } run (distance: number) { console.log(`直立行走:${distance}`) } } // Animal類,實(shí)現(xiàn)了 Eat 和 Run 兩個(gè)接口 class Animal implements Eat, Run { eat (food: string): void { console.log(`饑不擇食的吃:${food}`) } run (distance: number) { console.log(`爬行:${distance}`) } }
13.抽象類
abstract 定義抽象類,抽象類只能被繼承,不能通過 new 的方式創(chuàng)建實(shí)例對(duì)象
// 定義一個(gè)抽象類 Animal abstract class Animal { eat (food: string): void { console.log(`饑不擇食的吃:${food}`) } // 定義一個(gè)抽象方法 run,可以不需要方法體。 // 定義了抽象方法之后,子類中必須實(shí)現(xiàn)這個(gè)抽象方法 abstract run (distance: number): void } class Dog extends Animal { run(distance: number): void { console.log('四腳爬行', distance) } } const d = new Dog() d.eat('嘎嘎') // 饑不擇食的吃:嘎嘎 d.run(100) // 四腳爬行 100
14. 泛型 Generics
泛型是指在定義接口函數(shù)類的時(shí)候,沒有指定具體的類型,等到我們在使用的時(shí)候再去指定具體的類型的這種特征
// 這里聲明一個(gè)創(chuàng)建 number 類型數(shù)組的函數(shù) creatNumberArray function createNumberArray (length: number, value: number): number[] { // 這里的Array是 any 類型,所以要給它指定一個(gè) Number 類型 const arr = Array<number>(length).fill(value) return arr } // 這里聲明一個(gè)創(chuàng)建 String 類型數(shù)組的函數(shù) createStringArray function createStringArray (length: number, value: string): string[] { const arr = Array<string>(length).fill(value) return arr } // 因?yàn)樯厦娴膬蓚€(gè)函數(shù)代碼有冗余,所以這里我們可以使用 泛型 // 一般我們使用 T 來作為泛型參數(shù)的名稱,然后把函數(shù)中不明確的類型都改為 T 來做代表 function createArray<T> (length: number, value: T): T[] { const arr = Array<T>(length).fill(value) return arr } // 然后使用泛型的時(shí)候 傳遞 T 的類型 const res = creatArray<string>(3,'foo') // const res = createNumberArray(3, 100) // res => [100, 100, 100]
==============================分割線=============================
下面是結(jié)合vue3的項(xiàng)目寫法
Vue3+TS基礎(chǔ)語法
??????定義data
script標(biāo)簽上lang="ts"
定義一個(gè)類型type或者接口interface來約束data
可以使用ref或者toRefs來定義響應(yīng)式數(shù)據(jù)
使用ref在setup讀取的時(shí)候需要獲取xxx.value,但在template中不需要
使用reactive時(shí),可以用toRefs解構(gòu)導(dǎo)出,在template就可以直接使用了
<script lang="ts"> import { defineComponent, reactive, ref, toRefs } from 'vue'; type Todo = { id: number, name: string, completed: boolean } export default defineComponent({ const data = reactive({ todoList: [] as Todo[] }) const count = ref(0); console.log(count.value) return { ...toRefs(data) } }) </script>
??????定義props
props需要使用PropType泛型來約束。
<script lang="ts"> import { defineComponent, PropType} from 'vue'; interface UserInfo = { id: number, name: string, age: number } export default defineComponent({ props: { userInfo: { type: Object as PropType<UserInfo>, // 泛型類型 required: true } }, }) </script>
defineProps 和 defineEmits
注意:defineProps 和 defineEmits 都是只在
為了聲明 props 和 emits 選項(xiàng)且具備完整的類型推斷,可以使用 defineProps 和 defineEmits API,它們在 <script setup> 中都是自動(dòng)可用的:
- defineProps 和 defineEmits 都是只在 <script setup> 中才能使用的****編譯器宏。他們不需要導(dǎo)入,且會(huì)在處理 <script setup> 的時(shí)候被編譯處理掉。
- defineProps 接收與 props 選項(xiàng)相同的值,defineEmits 也接收 emits 選項(xiàng)相同的值。
- defineProps 和 defineEmits 在選項(xiàng)傳入后,會(huì)提供恰當(dāng)?shù)念愋屯茢唷?/li>
- 傳入到 defineProps 和 defineEmits 的選項(xiàng)會(huì)從 setup 中提升到模塊的范圍。因此,傳入的選項(xiàng)不能引用在 setup 范圍中聲明的局部變量。這樣做會(huì)引起編譯錯(cuò)誤。但是,它可以引用導(dǎo)入的綁定,因?yàn)樗鼈円苍谀K范圍內(nèi)。
父組件
//父組件 <script setup lang="ts"> import TestPropsPmit from './components/test-props-emit/index.vue'; import { ref } from 'vue'; // 定義字符串變量 const msg = ref('歡迎使用vite!') // 調(diào)用事件 const handleChange = (params:string) =>{ console.log(params); } </script> <template> <TestPropsPmit :msg="msg" @on-change="handleChange"></TestPropsPmit> </template>
子組件
//子組件 <template> <p>{{props.msg}}</p> <button @click="handleClick">點(diǎn)擊我調(diào)用父組件方法</button> </template> <script setup lang="ts"> const props = defineProps({ msg:{ type: String, default: () => '默認(rèn)值' } }) const emit = defineEmits(['on-change', 'update']) const handleClick = () =>{ emit('on-change', '父組件方法被調(diào)用了') } </script>
子組件暴露屬性和方法,給父組件引用
<script setup lang="ts"> function testChild():void{ console.log('子組件方法testChild被調(diào)用了'); } const b = ref(2) // 統(tǒng)一暴露屬性 defineExpose({ obj:{name: '張三', age: 2300}, b, testChild }) </script>
父組件調(diào)用子組件方法和屬性
<template> <TestPropsEmit ref="propsEmitRef" :msg='msg' @on-change="handleChange"> </TestPropsEmit> </template> <script setup lang="ts"> import TestPropsEmit from './components/test-props-emit/index.vue'; import {ref, onMounted} from 'vue'; const msg = ref('歡迎學(xué)習(xí)vite') const handleChange = (params:string)=>{ console.log(params); } const propsEmitRef = ref() onMounted(()=>{ console.log(propsEmitRef.value.child); }) </script>
??????定義methods
<script lang="ts"> import { defineComponent, reactive, ref, toRefs } from 'vue'; type Todo = { id: number, name: string, completed: boolean } export default defineComponent({ const data = reactive({ todoList: [] as Todo[] }) // 約束輸入和輸出類型 const newTodo = (name: string):Todo => { return { id: this.items.length + 1, name, completed: false }; } const addTodo = (todo: Todo): void => { data.todoList.push(todo) } return { ...toRefs(data), newTodo, addTodo } }) </script>
vue-router
- createRouter創(chuàng)建router實(shí)例
- router的模式分為:
- createWebHistory -- history模式
- createWebHashHistory -- hash模式
- routes的約束類型是RouteRecordRaw
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; import Home from '../views/Home.vue'; const routes: Array< RouteRecordRaw > = [ { path: '/', name: 'Home', component: Home, }, { path: '/about', name: 'About', component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') } ]; const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }); export default router;
擴(kuò)展路由額外屬性
在實(shí)際項(xiàng)目開發(fā)中,常常會(huì)遇到這么一個(gè)場景,某一個(gè)路由是不需要渲染到側(cè)邊欄導(dǎo)航上的,此時(shí)我們可以給該路由添加一個(gè)hidden屬性來實(shí)現(xiàn)。
在ts的強(qiáng)類型約束下,添加額外屬性就會(huì)報(bào)錯(cuò),那么我們就需要擴(kuò)展RouteRecordRaw類型。
在setup中使用
需要導(dǎo)入useRouter創(chuàng)建一個(gè)router實(shí)例。
<script lang="ts"> import { useRouter } from 'vue-router'; import { defineComponent } from 'vue'; export default defineComponent({ setup () { const router = useRouter(); goRoute(path) { router.push({path}) } } }) </script>
?????? vuex
使用this.$store
import { createStore } from 'vuex'; export type State = { count: number } export default createStore({ state: { count: 0 } });
需要?jiǎng)?chuàng)建一個(gè)聲明文件vuex.d.ts
// vuex.d.ts import {ComponentCustomProperties} from 'vue'; import {Store} from 'vuex'; import {State} from './store' declare module '@vue/runtime-core' { interface ComponentCustomProperties { $store: Store<State> } }
在setup中使用
- 定義InjecktionKey
- 在安裝插件時(shí)傳入key
- 在使用useStore時(shí)傳入
import { InjectionKey } from 'vue'; import { createStore, Store } from 'vuex'; export type State = { count: number } // 創(chuàng)建一個(gè)injectionKey export const key: InjectionKey<Store<State>> = Symbol('key');
// main.ts import store, { key } from './store'; app.use(store, key);
<script lang="ts"> import { useStore } from 'vuex'; import { key } from '@/store'; export default defineComponent({ setup () { const store = useStore(key); const count = computed(() => store.state.count); return { count } } }) </script>
模塊
新增一個(gè)todo模塊。導(dǎo)入的模塊,需要是一個(gè)vuex中的interface Module的對(duì)象,接收兩個(gè)泛型約束,第一個(gè)是該模塊類型,第二個(gè)是根模塊類型。
// modules/todo.ts import { Module } from 'vuex'; import { State } from '../index.ts'; type Todo = { id: number, name: string, completed: boolean } const initialState = { todos: [] as Todo[] }; export type TodoState = typeof initialState; export default { namespaced: true, state: initialState, mutations: { addTodo (state, payload: Todo) { state.todos.push(payload); } } } as Module<TodoState, State>; //Module<S, R> S 該模塊類型 R根模塊類型
// index.ts export type State = { count: number, todo?: TodoState // 這里必須是可選,不然state會(huì)報(bào)錯(cuò) } export default createStore({ state: { count: 0 } modules: { todo } });
使用:
setup () { console.log(store.state.todo?.todos); }
?????? 在setup如何定義變量(字符串,對(duì)象,數(shù)組)
<template> <h2>{{count}} {{user.name}}</h2> <span v-for="(item, index) in arr" :key="index">{{item}}</span> <button @click="setName">點(diǎn)擊我增加</button> </template> <script setup lang="ts"> import { ref, reactive } from 'vue'; // 字符串變量 const count = ref(0) // 對(duì)象 let user = reactive({ name: '張三' }) // 數(shù)組 let arr = reactive(['1', '2', '3']) // 綜合定義方案 const originData = reactive({ count: 0, user:{ name: '張三' }, arr: ['1', '2', '3'] }) // 方法 const setName = ()=>{ count.value++ user.name = '李四' } </script>
Watch和WatchEffect
1、基本使用方法:
<template> <p>{{originData.count}} {{originData.user.name}}</p> <p v-for="(item, index) in originData.arr" :key="index">{{item}}</p> <button @click="incriment">點(diǎn)擊我count增加</button> </template> <script setup lang="ts"> import { ref, reactive, watchEffect, watch } from 'vue'; const count = ref(0) const user = reactive({name: '張三'}) const arr = reactive([1,2,3,4]) // 綜合定義方案 const originData = reactive({ count: 0, user:{ name: '張三' }, arr:[1,2,3,4] }) const incriment = ()=>{ originData.count++ count.value++ originData.user.name = '李四' } // 默認(rèn)頁面更新之前立即執(zhí)行監(jiān)聽,懶執(zhí)行開始 watchEffect(() => console.log(count.value)) // 默認(rèn)監(jiān)聽數(shù)據(jù)變化后的值,頁面更新后不會(huì)立即執(zhí)行 watch(count, (n, o) => { console.log('watch', n, o); }) // 監(jiān)聽多個(gè)值 watch([count, originData.user], (newValues, prevValues) => { console.log(newValues[0], newValues[1].name) }) // 立即監(jiān)聽 watch([count, originData.user], (newValues, prevValues) => { console.log(newValues[0], newValues[1].name) }, {deep: true, immediate: true}) </script>
提示:
watch與 watchEffect 比較,推薦watch監(jiān)聽
watch: 頁面更新后不會(huì)立即執(zhí)行,而watchEffect 它會(huì)執(zhí)行;
??????Vue3生命周期調(diào)用
在 setup () 內(nèi)部調(diào)用生命周期鉤子:
- 選項(xiàng)式 API Hook inside setup
- beforeCreate Not needed* 不需要
- created Not needed* 不需要
- beforeMount onBeforeMount 掛載之前
- mounted onMounted 頁面加載完成時(shí)執(zhí)行
- beforeUpdate onBeforeUpdate
- updated onUpdated
- beforeUnmount onBeforeUnmount
- unmounted onUnmounted 頁面銷毀時(shí)執(zhí)行
- errorCaptured onErrorCaptured
- renderTracked onRenderTracked
- renderTriggered onRenderTriggered
- activated onActivated
- deactivated onDeactivated
<script setup lang="ts"> import { onMounted, onActivated, onUnmounted, onUpdated, onDeactivated } from 'vue'; // 讀取環(huán)境變量 const mode = import.meta.env; // import HeadMenu from '@/components/head-menu/index.vue'; onMounted(() => { console.log("組件掛載") }) onUnmounted(() => { console.log("組件卸載") }) onUpdated(() => { console.log("組件更新") }) onActivated(() => { console.log("keepAlive 組件 激活") }) onDeactivated(() => { console.log("keepAlive 組件 非激活") }) </script>
加??????為必用的東西,可以多看看
總結(jié)
到此這篇關(guān)于TypeScript快速上手語法及結(jié)合vue3用法詳解的文章就介紹到這了,更多相關(guān)TS語法及結(jié)合vue3用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js獲取html頁面節(jié)點(diǎn)方法(遞歸方式)
這篇文章主要介紹了js使用遞歸方式獲取html頁面節(jié)點(diǎn)的方法,大家可以參考使用吧2013-12-12JS實(shí)現(xiàn)雙擊屏幕滾動(dòng)效果代碼
這篇文章主要介紹了JS實(shí)現(xiàn)雙擊屏幕滾動(dòng)效果代碼,涉及JavaScript鼠標(biāo)事件的響應(yīng)及頁面元素屬性的動(dòng)態(tài)變換技巧,需要的朋友可以參考下2015-10-10JavaScript字符串轉(zhuǎn)數(shù)字的多種方法總結(jié)
在 JavaScript 開發(fā)中,我們經(jīng)常需要將字符串轉(zhuǎn)換為數(shù)字,例如從輸入框獲取用戶輸入后進(jìn)行數(shù)學(xué)計(jì)算,JavaScript 提供了多種方法來實(shí)現(xiàn)這一功能,如 parseInt、parseFloat、Number 等,本文將詳細(xì)介紹這些方法的使用方式、適用場景以及可能的坑,需要的朋友可以參考下2025-03-03javascript實(shí)現(xiàn)5秒倒計(jì)時(shí)并跳轉(zhuǎn)功能
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)5秒倒計(jì)時(shí)并跳轉(zhuǎn)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06基于JavaScript實(shí)現(xiàn)圖片預(yù)覽功能
在本文中,我們將學(xué)習(xí)如何使用 JavaScript 實(shí)現(xiàn)一個(gè)簡單的圖片預(yù)覽功能,我們將使用 HTML、CSS 和 JavaScript 來創(chuàng)建一個(gè)用戶界面,用戶可以輸入圖片 URL 并實(shí)時(shí)預(yù)覽圖片,感興趣的小伙伴跟著小編一起來看看吧2024-07-07