【vue3 setup composition Api 的 Ts 类型声明使用 & 讲解】

46 篇文章 6 订阅
10 篇文章 0 订阅

该文章未归纳完,那么多API肯定也说不完。。不过也涵盖了主要的组合式 API 的 TS类型。

核心:大部分都是运用API函数泛型来定义类型。

本文包含API的TS内容:

ref、reactive、customRef、provide、inject、computed、watch、defineExpose、defineProps、defineEmits、withDefaults ....


# 父组件相关的

<template>
  <el-button @click="onsub">测试</el-button>
  <input type="text" @change="handleChange" />
  <child ref='childRef' :child='2' :strData='"1"' :arrFor="[]" @elPsyKongroo='onsub'></child>
</template>
<script lang='ts' setup>
import child from './child.vue'
import { ref,Ref,reactive,computed,customRef,watch,provide } from "vue";

//> ref
// interface Ref<T> {
//   value: T
// }
// function ref<T>(value: T): Ref<T>
const year = ref<string | number>('2020')
// 如果泛型的类型未知,则建议将 ref 转换为 Ref<T>:
function useState<State extends string>(initial: State) {
  const state = ref(initial) as Ref<State> // state.value -> State extends string
  return state
}

//> reactive
interface Book {
  title: string
  year?: number
}
const book = reactive<Book>({title:'唉,真有氏的怀表怎么停了!'})
// function reactive<T extends object>(target: T): UnwrapNestedRefs<T>

//> customRef
// function customRef<T>(factory: CustomRefFactory<T>): Ref<T>
// type CustomRefFactory<T> = (
//   track: () => void,
//   trigger: () => void
// ) => {
//   get: () => T
//   set: (value: T) => void
// }
function useDebouncedRef(value:string, delay = 200) {
  return customRef<string>((track, trigger) => {
    return {
      get() {
        return value
      },
      set(newValue) {
        value = newValue
      }
    }
  })
}
let a23 = useDebouncedRef('heelo1')
a23.value = '123'


//> provide 与 inject   // inject示例在同级child.vue里
// interface InjectionKey<T> extends Symbol {}
// function provide<T>(key: InjectionKey<T> | string, value: T): void
provide('static',year)
provide('pbook',book)
provide('changeFn',onsub)
//! 有时候可能需要在子组件修改响应式的数据,此时provide一个方法给子组件调用



//> computed
let count = ref(0)
const doubleCount = computed<number>(() => count.value + 2)

//> watch
watch<number>(count,()=>{})
// watch<Ref<number>>(count,()=>{}) // 也可以
interface ReactiveData2{
  content2: {
    count2: number
  }
}
let refData = ref(1)
let reactiveData = reactive({content:{count:110}})
let reactiveData2 = reactive<ReactiveData2>({content2:{count2:1}})
watch<[Ref<number>,() => number,ReactiveData2]>([refData, ()=>reactiveData.content.count,reactiveData2], ([a,b,c], oldValue) => {
  console.log(a,b,c, oldValue)
})


// defineExpose 暴露的内容
// let childRef = ref()
// setTimeout(() => {
//   console.log(childRef.value.ex1); // 如果是子组件的ref对象数据,会自动解包 .value
// }, 1000);

function handleChange(el) {
  console.log((el.target as HTMLInputElement).value)
  console.log(el.target.value)
}
function onsub(val) {
  console.log(val);
  year.value = 2036
  book.title = '掌管未来女神的作战计划 El psy kongroo'
}
</script>

# 子组件相关的

<template>
  <div class="studyContent">
    <div>{{a}}</div>
    <div>{{a2}}</div>
    <div>{{pbook.title}}</div>
  </div>
</template>
<script lang='ts' setup>
import { inject,ref,Ref } from "vue";

//! defineProps 或 defineEmits 只能是要么使用`运行时声明`,要么使用`类型声明`。同时使用两种声明方式会导致编译报错。

//> defineProps
// 仅限类型的 defineProps 声明的不足之处在于,它没有可以给 props 提供默认值的方式。为了解决这个问题,提供了 withDefaults 编译器宏:
//? 运行时声明 的方式只能限制参数类型,无法限制是否必传、和默认值
// const props = defineProps({
//   child: String,
//   sda: String, //undefined
//   strData: String,
//   arrFor: Array
// })

//? 类型声明 的方式1:能限制是否必传 > defineProps 单独使用该api
// interface arrfor {
//   name:string,
//   children?:Array<arrfor>
// }
// const props = defineProps<{
//   child?: string|number,
//   sda?: string, //undefined
//   strData?: string,
//   arrFor: []
// }>();
// console.log(props);

//? 类型声明 的方式2:能限制是否必传,以及默认值
interface Props {
  child: string|number,
  sda?: string, // 未设置默认值,为 undefined
  strData: string,
  msg?: string
  labels?: string[],
  obj?:{a:number}
}
const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two'],
  obj: () => { return {a:2} }
})
console.log(props,props.msg);


//> defineEmits
// // 等效this.$emit('eventName','data')
// const emits = defineEmits(['update', 'delete'])
// emits('delete','测试')

// emits的类型声明写法,()的e id只是形参名字,不影响其他。
const emit = defineEmits<{
  (e: 'elPsyKongroo', id: number): void
  (e: 'update', value: string): void
}>()
setTimeout(() => {
  // emit('elPsyKongroo', 2)
}, 1000*2);

//> defineExpose
interface exFace {
  ex1:Ref<string>,
  ex2?:number
}
let ex1 = ref('1')
let exObj:exFace = {
  ex1,
}
// 源码类型: const defineExpose: (exposed?: Record<string, any>) => void
defineExpose(exObj)


//> inject
// interface InjectionKey<T> extends Symbol {}
// // 没有默认值
// function inject<T>(key: InjectionKey<T> | string): T | undefined
// // 有默认值
// function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T

// // 有工厂函数
// function inject<T>(
//   key: InjectionKey<T> | string,
//   defaultValue: () => T,
//   treatDefaultAsFactory: true
// ): T
let defaultFn = inject('ab12',()=>'雏见泽'+'棉流',true) 
console.log(defaultFn);


interface Book {
  title: string
  year?: number
}
let a = inject<Ref>('static') // 无默认值
  //! 即使在子组件可以直接修改,但最好不要这么做,将会影响到provide的父组件以及其他所有inject的子组件。
  //! 这会导致 溯源 非常麻烦,所以修改方式统一为在父组件provide一个方法,子组件调用进行修改!
  // a.value = '直接作死修改'
let pbook = inject<Book>('pbook') // 无默认值
let changeFn:(val:string)=>void = inject('changeFn') // 无默认值
let a2 = inject('static2','????') // 有默认值
let a3 = inject('static3') // 无默认值且未找到则为 undefined
let globalGuide = inject('guide') // 访问全局的

setTimeout(() => {
  changeFn('injectFn传参')
}, 5000);
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值