TypeScript进阶

目录

TypeScript 与 Vue

文档说明

vscode 插件说明

准备页面基本结构

defineProps与Typescript

defineEmits与Typescript

ref与Typescript

reactive与Typescript

computed与Typescript

事件对象与Typescript

模板Ref与Typescript

可选链操作符和非空断言


TypeScript 与 Vue

文档说明

英文文档:TypeScript with Composition API | Vue.js

中文文档:TypeScript 与组合式 API | Vue.js

vscode 插件说明

 vue3 配合 ts 中,还需要额外安装一个 vscode 插件:Typescript Vue Plugin (Volar)

 

准备页面基本结构

main.ts

import { createApp } from 'vue'

import App from './App.vue'

const app = createApp(App)

app.mount('#app')

App.vue

<script setup lang="ts">

</script>

<template>

  <div>

    <h1>我是 App 组件</h1>

  </div>

</template>

defineProps与Typescript

目标:掌握 defineProps 如何配合 ts 使用

defineProps js 写法

App.vue

<script setup lang="ts">

import Child from './components/Child.vue'

import { ref } from 'vue'

const money = ref(100)

</script>

<template>

  <div style="border: 3px solid #ccc;margin: 10px;">

    <h1>我是 App 组件 --- {{ money }}</h1>

    <Child :money="money"></Child>

  </div>

</template>

components/Child.vue

<script setup lang="ts">

defineProps({

  money: {

    type: Number, // 定义类型

    required: true, // 是否必传

    // default: 10 // 默认值

  }

})

</script>

<template>

  <div style="border: 3px solid #ccc;margin: 10px;">

    <h3>我是 Child 组件 --- {{ money }}</h3>

  </div>

</template>

defineProps ts 写法

通过 defineProps 函数的泛型,指定了 prop 的名字和类型。(vue 内部做了一些处理)

components/Child.vue

<script setup lang="ts">

// 1. 只要写在泛型里面的 prop 类型,就代表是必填的了

defineProps<{

  money: number

}>()

// 2. 如果 prop 不是必传的

defineProps<{

  money?: number

}>()

// 3. 通过解构指定默认值

const { money = 10 } = defineProps<{

  money?: number

}>()

</script>

<template>

  <div style="border: 3px solid #ccc;margin: 10px;">

    <h3>我是 Child 组件 --- {{ money }}</h3>

  </div>

</template>

如果提供的默认值需要在模板中渲染,需要额外添加配置

Reactivity Transform | Vue.js

vite.config.ts

export default {

  plugins: [

    vue({

      reactivityTransform: true

    })

  ]

}

defineEmits与Typescript

目标:掌握 defineEmit 如何配合 ts 使用

defineEmits js 写法

App.vue

<script setup lang="ts">

import { ref } from 'vue'

import Child from './components/Child.vue'

const money = ref(100)

// 挣钱

const makeMoney = (childMoney: number) => {

  money.value = money.value + childMoney

}

</script>

<template>

  <div style="border: 3px solid #ccc;margin: 10px;">

    <h1>我是 App 组件</h1>

    <Child :money="money" @makeMoney="makeMoney"></Child>

  </div>

</template>

components/Child.vue

<script setup lang="ts">

const emit = defineEmits(['makeMoney'])

const makeMoney = () => {

  emit('makeMoney', 10)

}

</script>

<template>

  <div style="border: 3px solid #ccc;margin: 10px;">

    <h3>我是 Child 组件 --- {{ money }}</h3>

    <button @click="makeMoney">挣钱</button>

  </div>

</template>

defineEmits ts 写法

js 的写法只是接收了传递过来的自定义事件的名字。

通过 defineEmits 函数的泛型:指定了自定义事件的名字,还指定了自定义事件函数的参数和返回值的类型。(vue 内部做了一些处理)

<script setup lang="ts">

// defineEmits 传入对象类型,对象类型中是一个一个的匿名函数类型,这个对象类型不是用来直接给自定义事件数据定义的

// vue内部拿这个对象类型后要做组装处理,然后给父组件传递过来的自定义事件数据定义类型

// 语法

// const emit = defineEmits<{

//   (e: '自定义事件名', 自定义事件函数参数: 自定义事件函数参数类型): 自定义事件函数返回值类型

// }>()

const emit = defineEmits<{

  (e: 'makeMoney', childMoney: number): void

}>()

const makeMoney = () => {

  emit('makeMoney', 10)

}

</script>

<template>

  <div style="border: 3px solid #ccc;margin: 10px;">

    <h3>我是 Child 组件 --- {{ money }}</h3>

    <button @click="makeMoney">挣钱</button>

  </div>

</template>

指定类型的好处:使用 emit 触发自定义事件时,不会传错参数。

ref与Typescript

目标:掌握 ref 配合 ts 如何使用

  1. 如果是简单数据类型,通过泛型指定值的类型,并且该类型可以省略

App.vue

<script setup lang="ts">

import { ref } from 'vue'

const money = ref<number>(100)

// 相当于

const money = ref(100)

</script>

<template>

  <div>

    <h1>我是 App 组件 --- {{ money }}</h1>

  </div>

</template>

2.如果是复杂数据类型,通过泛型指定值的类型,并且推荐指定类型

App.vue

<script setup lang="ts">

import { ref } from 'vue'

// 不指定类型,会报错,并且没有提示

type User = {

  id: number

  name: string

  age: number

}

const list = ref<User[]>([])

// 模拟后端返回数据

setTimeout(() => {

  list.value = [

    { id: 1, name: 'zs', age: 18 },

    { id: 2, name: 'ls', age: 19 }

  ]

}, 1000)

</script>

<template>

  <div>

    <h1>我是 App 组件</h1>

  </div>

</template>

reactive与Typescript

目标:掌握 reactive 配合 ts 如何使用

App.vue

<script setup lang="ts">

import { reactive } from 'vue'

// reactive 只适用于给具有明确属性的复杂数据。它可以自己推断类型,所以不需要指定类型

const user = reactive({

  id: 1,

  name: 'zs',

  age: 18

})

// 如果指定类型,有两种写法

type User = {

  id: number

  name: string

  age?: number

}

// 写法一

const user: User = reactive({

  id: 1,

  name: 'zs',

  age: 18

})

// 写法二(泛型)

const user = reactive<User>({

  id: 1,

  name: 'zs',

  age: 18

})

</script>

<template>

  <div>

    <h1>我是 App 组件</h1>

  </div>

</template>

computed与Typescript

目标:掌握 computed 配合 typescript 如何使用

通过泛型可以指定 computed 计算属性返回值的类型,通常可以省略,因为它可以根据计算属性的返回值类型自动推导出来。

App.vue

<script setup lang="ts">

import { ref, computed } from 'vue'

const count = ref(100)

const doubleCount = computed(() => {

  return count.value * 2

})

const doubleCount = computed<number>(() => {

  return count.value * 2

})

</script>

<template>

  <div>

    <h1>我是 App 组件 --- {{ count }} --- {{ doubleCount }}</h1>

  </div>

</template>

事件对象与Typescript

目标:掌握事件对象配合 typescript 如何使用

App.vue

<script setup lang="ts">

// 1. 想要有事件对象上的属性提示,需要给事件对象指定类型(可以通过鼠标悬停到绑定的事件上,查看事件对象的类型)

const handleChange = (event: Event) => {

  console.log(event.target)

}

// 1. 想要有事件目标源上的属性提示,需要给事件目标源做类型断言(可以通过 document.createElement 创建该元素,查看元素的类型)

const handleChange = (event: Event) => {

  // const input = document.createElement('input')

  console.log((event.target as HTMLInputElement).value)

}

</script>

<template>

  <div>

    <h1>我是 App 组件</h1>

    <input type="text" @change="handleChange" />

  </div>

</template>

模板Ref与Typescript

目标:掌握 ref 操作 DOM 时如何配合 Typescript 使用

App.vue

<script setup lang="ts">

import { ref } from 'vue'

const h1Ref = ref(null)

const getElement = () => {

  // 报错,因为初始值是 null,无法从 null 身上获取其他属性。

  console.log(h1.value.innerHTML)

}

// 通过 ref 获取 DOM 时,要通过泛型设置 DOM 类型

const h1Ref = ref<HTMLHeadingElement | null>(null)

const getElement = () => {

  if (h1Ref.value) {

    console.log(h1Ref.value.innerHTML)

  }

}

</script>

<template>

  <div>

    <h1 ref="h1Ref">我是 App 组件</h1>

    <button @click="getH1">获取 h1 元素</button>

  </div>

</template>

可选链操作符和非空断言

目标:掌握 js 中的可选链操作符语法,掌握 ts 中的非空断言的使用语法

访问对象的深层属性时,但是不确定属性是否存在时:

类型守卫:对象中的某个属性存在时,才继续访问它后面的属性

可选链操作符( ?. ):对象中的某个属性存在时,才继续访问它后面的属性

非空断言:如果我们明确的知道对象的属性一定不会为空,那么可以使用非空断言 !

App.vue

<script setup lang="ts">

import { ref } from 'vue'

const h1Ref = ref<null | HTMLHeadingElement>(null)

const changeElement = () => {

  // 方式一:类型守卫(使用if判断)

  if (h1.value) {

    console.log(h1.value.innerHTML)

  }

  // 方式二:可选链操作符(无法做赋值操作)

  console.log(h1.value?.innerHTML)

  // 方式三:非空断言

  // 使用非空断言告诉 ts,h1.value 一定不为空

  // 注意:非空断言一定要确保有该属性才能使用,不然使用非空断言会导致 bug

  console.log(h1.value!.innerHTML)

}

</script>

<template>

  <div>

    <h1>我是 App 组件</h1>

    <button ref="h1Ref" @click="changeElement">修改 h1 元素 innerHTML 内容</button>

  </div>

</template>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值