小言_互联网的博客

TypeScript快速上手语法+结合vue3用法

1664人阅读  评论(0)

 TypeScript快速上手语法+结合vue3用法

        前言:    

        本篇内容不涉及TypeScript安装以及配置,具体安装及配置篇可以看下面目录,本篇只涉及TypeScript语法相关内容,及结合vue3的用法。不讲废话,简单直接直接开撸。

目录

     TypeScript的具体安装及配置

 TypeScript快速上手语法+结合vue3用法

1、定义原始类型 

2、定义object 类型

3.定义数组类型 

4.定义元祖类型

5.定义enum 类型

6.定义函数类型

7.定义任意类型

8.隐式类型推断

9.类型断言

 10、 接口 interface

11、类 Class

12.类与接口

13.抽象类

   14. 泛型 Generics

Vue3+TS基础语法

🧨🧨🧨定义data

    🧨🧨🧨定义props

    🧨🧨🧨定义methods

vue-router

    在setup中使用

   🧨🧨🧨 vuex

在setup中使用

    模块

🧨🧨🧨 在setup如何定义变量(字符串,对象,数组)

Watch和WatchEffect

Vue3生命周期调用 


 

1、定义原始类型 


  
  1. const a: string = 'foo'
  2. const b: number = 100
  3. const c: boolean = true
  4. const d: void = undefined
  5. const e: null = null
  6. const f: undefined = undefined
  7. const g: symbol = Symlol()

2、定义object 类型


  
  1. const foo: object = function ( ) {} // [] // {}
  2. const obj: { foo: number, bar: string } = { foo: 123, bar: 'string' }

3.定义数组类型 


  
  1. // 第一种定义方式,元素类型设置为 *number*
  2. const arr1: Array<number> = [ 1, 2, 3]
  3. // 第二种定义方式,较为常见
  4. const arr2: number[] = [ 1, 2, 3]
  5. // 例子
  6. function sum (... args: number[]) {
  7. // 传统做法是要判断传入的参数是否是数字,
  8. TypeScript中只需要像上面这样对参数做一个类型注解,就行了
  9. return args. reduce(prev, current) => prev + current, 0)
  10. }
  11. sum( 1, 2, 3, 'foo') // 这里传入了一个非数字的值就会报错

4.定义元祖类型


  
  1. const tuple: [number, string] = [ 18, 'foo']
  2. // const tuple: [number, string] = [18, 18] 类型不匹配,会报错
  3. // const tuple: [number, string] = [18, 'foo', 'xxx'] 数量不匹配,会报错
  4. // 访问
  5. const age = tuple[ 0]
  6. const name = tuple[ 1]
  7. // 解构
  8. const [age, name] = tuple

5.定义enum 类型


  
  1. // enum 对象的属性可以不用赋值,默认从0开始递增,
  2. 也可以赋值 Draft = 5,后面的就从 5开始递增
  3. 也可以给具体的值,比如 Draft = 'xxx',这样后面的属性都要给具体的值
  4. enum PostStatus {
  5. Draft = 0,
  6. Unpublished = 1,
  7. Published = 2
  8. }
  9. const post = {
  10. title: 'Hello TypeScript',
  11. content: 'TypeScript is a typed superset of JavaScript.',
  12. status: PostStatus. Draft // 0 // 1 // 2
  13. }

6.定义函数类型


  
  1. // 声明式函数
  2. // 参数a和b是number类型,函数返回是string类型,
  3. // 参数后带问号代表是可选参数
  4. // 当参数数量不固定的时候可以使用rest运算符来接受参数,类型是一个值为number的数组
  5. function func1 ( a: number, b?: number, ... rest: number[]): string {
  6. return 'func1'
  7. }
  8. // 函数表达式定义函数
  9. const func2 = function ( a: number, b: number): string {
  10. return 'func2'
  11. }
  12. // 如果把一个函数作为参数传递,类似callback函数。
  13. function fntD( callback: (bl: boolean) => boolean) {
  14. callback( true)
  15. }
  16. function callback( bl: boolean): boolean {
  17. console. log(bl)
  18. return bl
  19. }
  20. const dResult = fntD(callback)

7.定义任意类型


  
  1. // value 可以接受任意类型
  2. function stringfy ( value: any) {
  3. return JSON. stringify(value)
  4. }
  5. stringify( 'string')
  6. stringify( 10)
  7. stringify( true)
  8. // foo 可以任意赋值
  9. let foo: any = 'string'
  10. foo = 100

8.隐式类型推断


  
  1. // age 赋值为 number 类型
  2. let age = 18 // number
  3. age = 'string' // 会警告错误,因为age是number类型
  4. let foo // 没有赋值,就是any类型
  5. foo = 100
  6. foo = 'string'

9.类型断言


  
  1. // 假定这个 nums 来自一个明确的接口
  2. const nums = [ 110, 120, 119, 112]
  3. // 这里TypeScript推断res的类型为 number|undefined
  4. // 因为它并不知道这个i到底在数组中有没有
  5. const res = nums. find( i => i > 0)
  6. // 这里就会报错警告
  7. const square = res * res
  8. // 如果我们直接 断言 这个 res 就是 number 类型
  9. const num1 = res as number
  10. // 这里就不会报错了
  11. const square = res * res

 10、 接口 interface

接口用来约定对象的结构,一个对象要实现一个接口,就必须拥有这个接口中所包含的所有成员


  
  1. interface Post {
  2. title: string
  3. content: string
  4. }
  5. function printPost ( post: Post) {
  6. console. log(post. title)
  7. console. log(post. content)
  8. }
  9. printPost({
  10. title: 'Hello TypeScript',
  11. content: 'A JavaScript superset'
  12. })
  13. // 特殊的接口成员 可选成员 只读成员
  14. interface Post{
  15. title: string
  16. content: string
  17. subtitle?: string // 加问号就是可选成员
  18. readonly summary: string // 加 readonly 就是只读成员
  19. }
  20. const hello: Post = {
  21. title: 'Hello TypeScript',
  22. content: 'A javascript superset',
  23. summary: 'a javascript'
  24. }
  25. hello. summary = 'other' // 会报错,因为 summary 是只读成员
  26. // 动态成员
  27. interface Cache {
  28. [ prop: string]: string
  29. }
  30. const cache: Cache = {}
  31. cache. foo = 'value1'
  32. cache. bar = 'value2'

11、类 Class


  
  1. Class Person {
  2. // 在这里赋值,和在构造函数中初始化必须两者选其一
  3. name: string // = 'init name' 这里可以直接初始化
  4. private age: number // 这里定义 age 为私有属性
  5. protected gender: boolean // 受保护的类型
  6. readonly national: string // 只读属性,一经初始化,不可更改
  7. constructor ( name: string, age: number) {
  8. // 需要在上面标注出构造函数中属性的类型
  9. this. name = name
  10. this. age = age
  11. this. gender = true
  12. this. national = national
  13. }
  14. sayHi ( msg: string): void {
  15. console. log( `I am ${this.name}, ${msg}`)
  16. console. log( this. age)
  17. }
  18. }
  19. const tom = new Person( 'tom', 18)
  20. console. log(tom. name) // tom
  21. console. log(tom. age) // 报错,因为 age 是私有属性,所以访问不到
  22. console. log(tom. gender) // 报错,因为 gender 是受保护的属性,这里访问不到
  23. // 在下方新声明一个类 student 继承与 Person
  24. class Student extends Person {
  25. constructor ( name: string, age: number) {
  26. super(name, age)
  27. console. log( this. gender) // 这里就一个访问到 受保护的属性 gender
  28. }

12.类与接口


  
  1. interface Eat {
  2. eat ( food: string): void
  3. }
  4. interface Run {
  5. run ( distance: number): void
  6. }
  7. // Person类,实现了 Eat 和 Run 两个接口
  8. class Person implements Eat, Run {
  9. eat ( food: string): void {
  10. console. log( `优雅的进餐:${food}`)
  11. }
  12. run ( distance: number) {
  13. console. log( `直立行走:${distance}`)
  14. }
  15. }
  16. // Animal类,实现了 Eat 和 Run 两个接口
  17. class Animal implements Eat, Run {
  18. eat ( food: string): void {
  19. console. log( `饥不择食的吃:${food}`)
  20. }
  21. run ( distance: number) {
  22. console. log( `爬行:${distance}`)
  23. }
  24. }

13.抽象类

    abstract 定义抽象类,抽象类只能被继承,不能通过 new 的方式创建实例对象


  
  1. // 定义一个抽象类 Animal
  2. abstract class Animal {
  3. eat ( food: string): void {
  4. console. log( `饥不择食的吃:${food}`)
  5. }
  6. // 定义一个抽象方法 run,可以不需要方法体。
  7. // 定义了抽象方法之后,子类中必须实现这个抽象方法
  8. abstract run ( distance: number): void
  9. }
  10. class Dog extends Animal {
  11. run( distance: number): void {
  12. console. log( '四脚爬行', distance)
  13. }
  14. }
  15. const d = new Dog()
  16. d. eat( '嘎嘎') // 饥不择食的吃:嘎嘎
  17. d. run( 100) // 四脚爬行 100

   14. 泛型 Generics

    泛型是指在定义接口函数类的时候,没有指定具体的类型,等到我们在使用的时候再去指定具体的类型的这种特征


  
  1. // 这里声明一个创建 number 类型数组的函数 creatNumberArray
  2. function createNumberArray ( length: number, value: number): number[] {
  3. // 这里的Array是 any 类型,所以要给它指定一个 Number 类型
  4. const arr = Array<number>(length). fill(value)
  5. return arr
  6. }
  7. // 这里声明一个创建 String 类型数组的函数 createStringArray
  8. function createStringArray ( length: number, value: string): string[] {
  9. const arr = Array<string>(length). fill(value)
  10. return arr
  11. }
  12. // 因为上面的两个函数代码有冗余,所以这里我们可以使用 泛型
  13. // 一般我们使用 T 来作为泛型参数的名称,然后把函数中不明确的类型都改为 T 来做代表
  14. function createArray<T> ( length: number, value: T): T[] {
  15. const arr = Array<T>(length). fill(value)
  16. return arr
  17. }
  18. // 然后使用泛型的时候 传递 T 的类型
  19. const res = creatArray<string>( 3, 'foo')
  20. // const res = createNumberArray(3, 100)
  21. // res => [100, 100, 100]

==============================分割线=============================

下面是结合vue3的项目写法

Vue3+TS基础语法

🧨🧨🧨定义data

  • script标签上lang="ts"

  • 定义一个类型type或者接口interface来约束data

  • 可以使用ref或者toRefs来定义响应式数据

  • 使用ref在setup读取的时候需要获取xxx.value,但在template中不需要

  • 使用reactive时,可以用toRefs解构导出,在template就可以直接使用了


  
  1. <script lang= "ts">
  2. import { defineComponent, reactive, ref, toRefs } from 'vue';
  3. type Todo = {
  4. id: number,
  5. name: string,
  6. completed: boolean
  7. }
  8. export default defineComponent({
  9. const data = reactive({
  10. todoList: [] as Todo[]
  11. })
  12. const count = ref( 0);
  13. console. log(count. value)
  14. return {
  15. ... toRefs(data)
  16. }
  17. })
  18. </script>

    🧨🧨🧨定义props

    props需要使用PropType泛型来约束。


  
  1. <script lang= "ts">
  2. import { defineComponent, PropType} from 'vue';
  3. interface UserInfo = {
  4. id: number,
  5. name: string,
  6. age: number
  7. }
  8. export default defineComponent({
  9. props: {
  10. userInfo: {
  11. type: Object as PropType< UserInfo>, // 泛型类型
  12. required: true
  13. }
  14. },
  15. })
  16. </script>
  17. 复制代码

defineProps 和 defineEmits 

    注意:defineProps 和 defineEmits 都是只在

    为了声明 props 和 emits 选项且具备完整的类型推断,可以使用 defineProps 和 defineEmits API,它们在 <script setup> 中都是自动可用的:

 

  •     defineProps 和 defineEmits 都是只在 <script setup> 中才能使用的****编译器宏。他们不需要导入,且会在处理 <script setup> 的时候被编译处理掉。
  •     defineProps 接收与 props 选项相同的值,defineEmits 也接收 emits 选项相同的值。
  •     defineProps 和 defineEmits 在选项传入后,会提供恰当的类型推断。
  •     传入到 defineProps 和 defineEmits 的选项会从 setup 中提升到模块的范围。因此,传入的选项不能引用在 setup 范围中声明的局部变量。这样做会引起编译错误。但是,它可以引用导入的绑定,因为它们也在模块范围内。

父组件 


  
  1. //父组件
  2. <script setup lang= "ts">
  3. import TestPropsPmit from './components/test-props-emit/index.vue';
  4. import { ref } from 'vue';
  5. // 定义字符串变量
  6. const msg = ref( '欢迎使用vite!')
  7. // 调用事件
  8. const handleChange = ( params:string) =>{
  9. console. log(params);
  10. }
  11. </script>
  12. <template>
  13. <TestPropsPmit :msg="msg" @on-change="handleChange"> </TestPropsPmit>
  14. </template>

 子组件


  
  1. //子组件
  2. <template>
  3. <p>{{props.msg}}</p>
  4. <button @click="handleClick">点击我调用父组件方法</button>
  5. </template>
  6. <script setup lang="ts">
  7. const props = defineProps({
  8. msg:{
  9. type: String,
  10. default: () => '默认值'
  11. }
  12. })
  13. const emit = defineEmits([ 'on-change', 'update'])
  14. const handleClick = ( ) =>{
  15. emit( 'on-change', '父组件方法被调用了')
  16. }
  17. </script>

 子组件暴露属性和方法,给父组件引用


  
  1. <script setup lang= "ts">
  2. function testChild( ): void{
  3. console. log( '子组件方法testChild被调用了');
  4. }
  5. const b = ref( 2)
  6. // 统一暴露属性
  7. defineExpose({
  8. obj:{ name: '张三', age: 2300},
  9. b,
  10. testChild
  11. })
  12. </script>

父组件调用子组件方法和属性 


  
  1. <template>
  2. <TestPropsEmit ref="propsEmitRef" :msg='msg' @on-change="handleChange"> </TestPropsEmit>
  3. </template>
  4. <script setup lang="ts">
  5. import TestPropsEmit from './components/test-props-emit/index.vue';
  6. import {ref, onMounted} from 'vue';
  7. const msg = ref( '欢迎学习vite')
  8. const handleChange = ( params:string)=>{
  9. console. log(params);
  10. }
  11. const propsEmitRef = ref()
  12. onMounted( ()=>{
  13. console. log(propsEmitRef. value. child);
  14. })
  15. </script>

    🧨🧨🧨定义methods


  
  1. <script lang= "ts">
  2. import { defineComponent, reactive, ref, toRefs } from 'vue';
  3. type Todo = {
  4. id: number,
  5. name: string,
  6. completed: boolean
  7. }
  8. export default defineComponent({
  9. const data = reactive({
  10. todoList: [] as Todo[]
  11. })
  12. // 约束输入和输出类型
  13. const newTodo = ( name: string): Todo => {
  14. return {
  15. id: this. items. length + 1,
  16. name,
  17. completed: false
  18. };
  19. }
  20. const addTodo = ( todo: Todo): void => {
  21. data. todoList. push(todo)
  22. }
  23. return {
  24. ... toRefs(data),
  25. newTodo,
  26. addTodo
  27. }
  28. })
  29. </script>

vue-router

  •     createRouter创建router实例
  •     router的模式分为:
  •     createWebHistory -- history模式
  •     createWebHashHistory -- hash模式
  •     routes的约束类型是RouteRecordRaw

  
  1. import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
  2. import Home from '../views/Home.vue';
  3. const routes: Array< RouteRecordRaw > = [
  4. {
  5. path: '/',
  6. name: 'Home',
  7. component: Home,
  8. },
  9. {
  10. path: '/about',
  11. name: 'About',
  12. component: () => import( /* webpackChunkName: "about" */ '../views/About.vue')
  13. }
  14. ];
  15. const router = createRouter({
  16. history: createWebHistory(process. env. BASE_URL),
  17. routes
  18. });
  19. export default router;

    扩展路由额外属性

    在实际项目开发中,常常会遇到这么一个场景,某一个路由是不需要渲染到侧边栏导航上的,此时我们可以给该路由添加一个hidden属性来实现。

    在ts的强类型约束下,添加额外属性就会报错,那么我们就需要扩展RouteRecordRaw类型。

    在setup中使用

    需要导入useRouter创建一个router实例。


  
  1. <script lang= "ts">
  2. import { useRouter } from 'vue-router';
  3. import { defineComponent } from 'vue';
  4. export default defineComponent({
  5. setup () {
  6. const router = useRouter();
  7. goRoute( path) {
  8. router. push({path})
  9. }
  10. }
  11. })
  12. </script>

   🧨🧨🧨 vuex

    使用this.$store


  
  1. import { createStore } from 'vuex';
  2. export type State = {
  3. count: number
  4. }
  5. export default createStore({
  6. state: {
  7. count: 0
  8. }
  9. });

    需要创建一个声明文件vuex.d.ts


  
  1. // vuex.d.ts
  2. import { ComponentCustomProperties} from 'vue';
  3. import { Store} from 'vuex';
  4. import { State} from './store'
  5. declare module '@vue/runtime-core' {
  6. interface ComponentCustomProperties {
  7. $store: Store< State>
  8. }
  9. }

在setup中使用

  •  定义InjecktionKey
  • 在安装插件时传入key
  • 在使用useStore时传入

  
  1. import { InjectionKey } from 'vue';
  2. import { createStore, Store } from 'vuex';
  3. export type State = {
  4. count: number
  5. }
  6. // 创建一个injectionKey
  7. export const key: InjectionKey< Store< State>> = Symbol( 'key');

  
  1. // main.ts
  2. import store, { key } from './store';
  3. app. use(store, key);

  
  1. <script lang= "ts">
  2. import { useStore } from 'vuex';
  3. import { key } from '@/store';
  4. export default defineComponent({
  5. setup () {
  6. const store = useStore(key);
  7. const count = computed( () => store. state. count);
  8. return {
  9. count
  10. }
  11. }
  12. })
  13. </script>

    模块

    新增一个todo模块。导入的模块,需要是一个vuex中的interface Module的对象,接收两个泛型约束,第一个是该模块类型,第二个是根模块类型。


  
  1. // modules/todo.ts
  2. import { Module } from 'vuex';
  3. import { State } from '../index.ts';
  4. type Todo = {
  5. id: number,
  6. name: string,
  7. completed: boolean
  8. }
  9. const initialState = {
  10. todos: [] as Todo[]
  11. };
  12. export type TodoState = typeof initialState;
  13. export default {
  14. namespaced: true,
  15. state: initialState,
  16. mutations: {
  17. addTodo (state, payload: Todo) {
  18. state. todos. push(payload);
  19. }
  20. }
  21. } as Module< TodoState, State>; //Module<S, R> S 该模块类型 R根模块类型

  
  1. // index.ts
  2. export type State = {
  3. count: number,
  4. todo?: TodoState // 这里必须是可选,不然state会报错
  5. }
  6. export default createStore({
  7. state: {
  8. count: 0
  9. }
  10. modules: {
  11. todo
  12. }
  13. });

    使用: 


  
  1. setup () {
  2. console. log(store. state. todo?. todos);
  3. }

🧨🧨🧨 在setup如何定义变量(字符串,对象,数组)


  
  1. <template>
  2. <h2>{{count}} {{user.name}}</h2>
  3. <span v-for="(item, index) in arr" :key="index">{{item}}</span>
  4. <button @click="setName">点击我增加</button>
  5. </template>
  6. <script setup lang="ts">
  7. import { ref, reactive } from 'vue';
  8. // 字符串变量
  9. const count = ref( 0)
  10. // 对象
  11. let user = reactive({
  12. name: '张三'
  13. })
  14. // 数组
  15. let arr = reactive([ '1', '2', '3'])
  16. // 综合定义方案
  17. const originData = reactive({
  18. count: 0,
  19. user:{
  20. name: '张三'
  21. },
  22. arr: [ '1', '2', '3']
  23. })
  24. // 方法
  25. const setName = ( )=>{
  26. count. value++
  27. user. name = '李四'
  28. }
  29. </script>

Watch和WatchEffect

    1、基本使用方法:


  
  1. <template>
  2. <p>{{originData.count}} {{originData.user.name}}</p>
  3. <p v-for="(item, index) in originData.arr" :key="index">{{item}}</p>
  4. <button @click="incriment">点击我count增加</button>
  5. </template>
  6. <script setup lang="ts">
  7. import { ref, reactive, watchEffect, watch } from 'vue';
  8. const count = ref( 0)
  9. const user = reactive({ name: '张三'})
  10. const arr = reactive([ 1, 2, 3, 4])
  11. // 综合定义方案
  12. const originData = reactive({
  13. count: 0,
  14. user:{
  15. name: '张三'
  16. },
  17. arr:[ 1, 2, 3, 4]
  18. })
  19. const incriment = ( )=>{
  20. originData. count++
  21. count. value++
  22. originData. user. name = '李四'
  23. }
  24. // 默认页面更新之前立即执行监听,懒执行开始
  25. watchEffect( () => console. log(count. value))
  26. // 默认监听数据变化后的值,页面更新后不会立即执行
  27. watch(count, (n, o) => {
  28. console. log( 'watch', n, o);
  29. })
  30. // 监听多个值
  31. watch([count, originData. user], (newValues, prevValues) => {
  32. console. log(newValues[ 0], newValues[ 1]. name)
  33. })
  34. // 立即监听
  35. watch([count, originData. user], (newValues, prevValues) => {
  36. console. log(newValues[ 0], newValues[ 1]. name)
  37. }, { deep: true, immediate: true})
  38. </script>

提示:

watch与 watchEffect 比较,推荐watch监听

watch: 页面更新后不会立即执行,而watchEffect 它会执行;

🧨🧨🧨Vue3生命周期调用 

在 setup () 内部调用生命周期钩子:

  •     选项式 API Hook inside setup
  •     beforeCreate Not needed* 不需要
  •     created Not needed* 不需要
  •     beforeMount onBeforeMount 挂载之前
  •     mounted onMounted 页面加载完成时执行
  •     beforeUpdate onBeforeUpdate
  •     updated onUpdated
  •     beforeUnmount onBeforeUnmount
  •     unmounted onUnmounted 页面销毁时执行
  •     errorCaptured onErrorCaptured
  •     renderTracked onRenderTracked
  •     renderTriggered onRenderTriggered
  •     activated onActivated
  •     deactivated onDeactivated

 


  
  1. <script setup lang= "ts">
  2. import { onMounted, onActivated, onUnmounted, onUpdated, onDeactivated } from 'vue';
  3. // 读取环境变量
  4. const mode = import. meta. env;
  5. // import HeadMenu from '@/components/head-menu/index.vue';
  6. onMounted( () => {
  7. console. log( "组件挂载")
  8. })
  9. onUnmounted( () => {
  10. console. log( "组件卸载")
  11. })
  12. onUpdated( () => {
  13. console. log( "组件更新")
  14. })
  15. onActivated( () => {
  16. console. log( "keepAlive 组件 激活")
  17. })
  18. onDeactivated( () => {
  19. console. log( "keepAlive 组件 非激活")
  20. })
  21. </script>

加🧨🧨🧨为必用的东西,可以多看看

 最后:

        待续....精力有限 持续更新中....


转载:https://blog.csdn.net/zhangxueyou2223/article/details/129216810
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场