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中只需要像上面這樣對參數(shù)做一個類型注解,就行了
return args.reduce(prev, current) => prev + current, 0)
}
sum(1, 2, 3, 'foo') // 這里傳入了一個非數(shù)字的值就會報錯4.定義元祖類型
const tuple: [number, string] = [18, 'foo'] // const tuple: [number, string] = [18, 18] 類型不匹配,會報錯 // const tuple: [number, string] = [18, 'foo', 'xxx'] 數(shù)量不匹配,會報錯 // 訪問 const age = tuple[0] const name = tuple[1] // 解構(gòu) const [age, name] = tuple
5.定義enum 類型
// enum 對象的屬性可以不用賦值,默認從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ù)后帶問號代表是可選參數(shù)
// 當(dāng)參數(shù)數(shù)量不固定的時候可以使用rest運算符來接受參數(shù),類型是一個值為number的數(shù)組
function func1 (a: number, b?: number, ...rest: number[]): string {
return 'func1'
}
// 函數(shù)表達式定義函數(shù)
const func2 = function (a: number, b: number): string {
return 'func2'
}
// 如果把一個函數(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 = 1008.隱式類型推斷
// age 賦值為 number 類型 let age = 18 // number age = 'string' // 會警告錯誤,因為age是number類型 let foo // 沒有賦值,就是any類型 foo = 100 foo = 'string'
9.類型斷言
// 假定這個 nums 來自一個明確的接口 const nums = [110, 120, 119, 112] // 這里TypeScript推斷res的類型為 number|undefined // 因為它并不知道這個i到底在數(shù)組中有沒有 const res = nums.find(i => i > 0) // 這里就會報錯警告 const square = res * res // 如果我們直接 斷言 這個 res 就是 number 類型 const num1 = res as number // 這里就不會報錯了 const square = res * res
10、 接口 interface
接口用來約定對象的結(jié)構(gòu),一個對象要實現(xiàn)一個接口,就必須擁有這個接口中所包含的所有成員
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 // 加問號就是可選成員
readonly summary: string // 加 readonly 就是只讀成員
}
const hello: Post = {
title: 'Hello TypeScript',
content: 'A javascript superset',
summary: 'a javascript'
}
hello.summary = 'other' // 會報錯,因為 summary 是只讀成員
// 動態(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 // 受保護的類型
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) // 報錯,因為 age 是私有屬性,所以訪問不到
console.log(tom.gender) // 報錯,因為 gender 是受保護的屬性,這里訪問不到
// 在下方新聲明一個類 student 繼承與 Person
class Student extends Person {
constructor (name: string, age: number) {
super(name, age)
console.log(this.gender) // 這里就一個訪問到 受保護的屬性 gender
}
12.類與接口
interface Eat {
eat (food: string): void
}
interface Run {
run (distance: number): void
}
// Person類,實現(xiàn)了 Eat 和 Run 兩個接口
class Person implements Eat, Run {
eat (food: string): void {
console.log(`優(yōu)雅的進餐:${food}`)
}
run (distance: number) {
console.log(`直立行走:${distance}`)
}
}
// Animal類,實現(xiàn)了 Eat 和 Run 兩個接口
class Animal implements Eat, Run {
eat (food: string): void {
console.log(`饑不擇食的吃:${food}`)
}
run (distance: number) {
console.log(`爬行:${distance}`)
}
}13.抽象類
abstract 定義抽象類,抽象類只能被繼承,不能通過 new 的方式創(chuàng)建實例對象
// 定義一個抽象類 Animal
abstract class Animal {
eat (food: string): void {
console.log(`饑不擇食的吃:${food}`)
}
// 定義一個抽象方法 run,可以不需要方法體。
// 定義了抽象方法之后,子類中必須實現(xiàn)這個抽象方法
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) // 四腳爬行 10014. 泛型 Generics
泛型是指在定義接口函數(shù)類的時候,沒有指定具體的類型,等到我們在使用的時候再去指定具體的類型的這種特征
// 這里聲明一個創(chuàng)建 number 類型數(shù)組的函數(shù) creatNumberArray
function createNumberArray (length: number, value: number): number[] {
// 這里的Array是 any 類型,所以要給它指定一個 Number 類型
const arr = Array<number>(length).fill(value)
return arr
}
// 這里聲明一個創(chuàng)建 String 類型數(shù)組的函數(shù) createStringArray
function createStringArray (length: number, value: string): string[] {
const arr = Array<string>(length).fill(value)
return arr
}
// 因為上面的兩個函數(shù)代碼有冗余,所以這里我們可以使用 泛型
// 一般我們使用 T 來作為泛型參數(shù)的名稱,然后把函數(shù)中不明確的類型都改為 T 來做代表
function createArray<T> (length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
// 然后使用泛型的時候 傳遞 T 的類型
const res = creatArray<string>(3,'foo')
// const res = createNumberArray(3, 100)
// res => [100, 100, 100]
==============================分割線=============================
下面是結(jié)合vue3的項目寫法
Vue3+TS基礎(chǔ)語法
??????定義data
script標(biāo)簽上lang="ts"
定義一個類型type或者接口interface來約束data
可以使用ref或者toRefs來定義響應(yīng)式數(shù)據(jù)
使用ref在setup讀取的時候需要獲取xxx.value,但在template中不需要
使用reactive時,可以用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 選項且具備完整的類型推斷,可以使用 defineProps 和 defineEmits API,它們在 <script setup> 中都是自動可用的:
- defineProps 和 defineEmits 都是只在 <script setup> 中才能使用的****編譯器宏。他們不需要導(dǎo)入,且會在處理 <script setup> 的時候被編譯處理掉。
- defineProps 接收與 props 選項相同的值,defineEmits 也接收 emits 選項相同的值。
- defineProps 和 defineEmits 在選項傳入后,會提供恰當(dāng)?shù)念愋屯茢唷?/li>
- 傳入到 defineProps 和 defineEmits 的選項會從 setup 中提升到模塊的范圍。因此,傳入的選項不能引用在 setup 范圍中聲明的局部變量。這樣做會引起編譯錯誤。但是,它可以引用導(dǎo)入的綁定,因為它們也在模塊范圍內(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ào)用父組件方法</button>
</template>
<script setup lang="ts">
const props = defineProps({
msg:{
type: String,
default: () => '默認值'
}
})
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實例
- 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;擴展路由額外屬性
在實際項目開發(fā)中,常常會遇到這么一個場景,某一個路由是不需要渲染到側(cè)邊欄導(dǎo)航上的,此時我們可以給該路由添加一個hidden屬性來實現(xiàn)。
在ts的強類型約束下,添加額外屬性就會報錯,那么我們就需要擴展RouteRecordRaw類型。
在setup中使用
需要導(dǎo)入useRouter創(chuàng)建一個router實例。
<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
}
});
需要創(chuàng)建一個聲明文件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
- 在安裝插件時傳入key
- 在使用useStore時傳入
import { InjectionKey } from 'vue';
import { createStore, Store } from 'vuex';
export type State = {
count: number
}
// 創(chuàng)建一個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>模塊
新增一個todo模塊。導(dǎo)入的模塊,需要是一個vuex中的interface Module的對象,接收兩個泛型約束,第一個是該模塊類型,第二個是根模塊類型。
// 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會報錯
}
export default createStore({
state: {
count: 0
}
modules: {
todo
}
});使用:
setup () {
console.log(store.state.todo?.todos);
}
?????? 在setup如何定義變量(字符串,對象,數(shù)組)
<template>
<h2>{{count}} {{user.name}}</h2>
<span v-for="(item, index) in arr" :key="index">{{item}}</span>
<button @click="setName">點擊我增加</button>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
// 字符串變量
const count = ref(0)
// 對象
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">點擊我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 = '李四'
}
// 默認頁面更新之前立即執(zhí)行監(jiān)聽,懶執(zhí)行開始
watchEffect(() => console.log(count.value))
// 默認監(jiān)聽數(shù)據(jù)變化后的值,頁面更新后不會立即執(zhí)行
watch(count, (n, o) => {
console.log('watch', n, o);
})
// 監(jiān)聽多個值
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: 頁面更新后不會立即執(zhí)行,而watchEffect 它會執(zhí)行;
??????Vue3生命周期調(diào)用
在 setup () 內(nèi)部調(diào)用生命周期鉤子:
- 選項式 API Hook inside setup
- beforeCreate Not needed* 不需要
- created Not needed* 不需要
- beforeMount onBeforeMount 掛載之前
- mounted onMounted 頁面加載完成時執(zhí)行
- beforeUpdate onBeforeUpdate
- updated onUpdated
- beforeUnmount onBeforeUnmount
- unmounted onUnmounted 頁面銷毀時執(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript字符串轉(zhuǎn)數(shù)字的多種方法總結(jié)
在 JavaScript 開發(fā)中,我們經(jīng)常需要將字符串轉(zhuǎn)換為數(shù)字,例如從輸入框獲取用戶輸入后進行數(shù)學(xué)計算,JavaScript 提供了多種方法來實現(xiàn)這一功能,如 parseInt、parseFloat、Number 等,本文將詳細介紹這些方法的使用方式、適用場景以及可能的坑,需要的朋友可以參考下2025-03-03
javascript實現(xiàn)5秒倒計時并跳轉(zhuǎn)功能
這篇文章主要為大家詳細介紹了javascript實現(xiàn)5秒倒計時并跳轉(zhuǎn)功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-06-06
基于JavaScript實現(xiàn)圖片預(yù)覽功能
在本文中,我們將學(xué)習(xí)如何使用 JavaScript 實現(xiàn)一個簡單的圖片預(yù)覽功能,我們將使用 HTML、CSS 和 JavaScript 來創(chuàng)建一個用戶界面,用戶可以輸入圖片 URL 并實時預(yù)覽圖片,感興趣的小伙伴跟著小編一起來看看吧2024-07-07

