Today , I will share script setupwith typescriptyou some of the techniques used in combination. If these techniques can help you, remember to give me a like 👍

Environment construction

The environment construction will not be introduced in detail here, you can directly use the official method to create

npm init vue@latest

This command will install and execute create-vue, it is the Vueofficial project scaffolding tool. You'll TypeScriptsee 测试hints for optional features like and support:

✔ Project name: … <your-project-name>
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes

Scaffolding project in ./<your-project-name>...
Done.

If you are not sure whether to enable a function, you can directly press the Enter key to select No. After the project is created, install the dependencies and start the development server with the following steps:

cd <your-project-name>
npm install
npm run dev

ref()

ref()Takes an internal value and returns a reactive, mutable refobject that has only one pointer to its internal value property .value.

type definition

function ref<T>(value: T): Ref<UnwrapRef<T>>
interface Ref<T
{
  value: T
}

Annotate the type for ref()

ref()There are three ways to label types:

  1. ref()Add a type to by the form of a generic parameter
import { ref } from 'vue'

const initCode = ref<string | number>('200')
  1. If it is a type that encounters complex points, you can customize interfaceit and then pass it in as a generic parameter
import { ref } from 'vue'

interface User {
  name: string
  age: string | number
}

const user = ref<User>({
  name:'前端开发爱好者',
  age: 20
})
  1. Specify a more complex type for the value within by using Refthis typeref
import { ref } from 'vue'
import type { Ref } from 'vue'

const initCode: Ref<string | number> = ref('200')

Three ways to recommend

It is recommended to use the 前两种method. The first two methods are actually 泛型marked in the form of

The third way requires an additional import:

import type { Ref } from 'vue'

So it is not very recommended (in line with the principle that one line can be written less is one line)

reactive()

reactive()A reactive proxy that returns an object.

type definition

function reactive<T extends object>(target: T): UnwrapNestedRefs<T>

Annotate types for reactive()

reactive()There are two ways to label types:

  1. Add the type directly to the declared variable
import { reactive } from 'vue'

interface User {
  name: string
  age: string | number
}

const user:User = reactive({
  name:"前端开发爱好者",
  age:'20'
})
  1. reactive()Add a type to by the form of a generic parameter
import { reactive } from 'vue'

interface User {
  name: string
  age: string | number
}

const user = reactive<User>({
  name:"前端开发爱好者",
  age:'20'
})

Two ways are recommended

不推荐Use reactive()a generic parameter of , because the return value of deep ref unpacking is handled with a different type than the generic parameter. 推荐直接给声明的变量添加类型.

computed()

Takes a getterfunction and returns a read-only reactive refobject, the return value of the getterfunction . It can also accept getan setobject with and functions to create a writable refobject .

type definition

// 只读
function computed<T>(
  getter: () => T,
  debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>

// 可写的
function computed<T>(
  options: {
    get: () => T
    set: (value: T) => void
  },
  debuggerOptions?: DebuggerOptions
): Ref<T>

Annotate the type for computed()

computed()There are two ways to label types:

  1. The type is deduced from the return value of its computed function
import { ref, computed } from 'vue'

const count = ref<number>(0)

// 推导得到的类型:ComputedRef<string>
const user = computed(() => count.value + '前端开发爱好者')
  1. Explicitly specify the computed()type
const user = computed<string>(() => {
  // 若返回值不是 string 类型则会报错
  return '前端开发爱好者'
}
)

Two ways are recommended

Although automatic type deduction is simple and fast, we still want 手动to remove 指定its type, which is more conducive to the maintainability of the code, so it is recommended that you use the generic parameter to explicitly specify the computed()type

defineProps()

To get full type inference support when declaring propsoptions , we can use the definePropsAPI, which will automatically be used script setupin

Annotate types for defineProps()

  1. Deduce the type from its arguments:
const props = defineProps({
  name: { typeString, required: true },
  age: Number
})
  1. propsThe type of is defined by a generic parameter
const props = defineProps<{
  name: string
  age?: number
}>()

Of course, we can also define the above generic parameters as a separateinterface

interface Props {
  name: string
  age?: number
}

const props = defineProps<Props>()

Although the above two methods can be very convenient 标注类型, they lose the ability to propsdefine default values.

At present, the official solution has also been given, but this solution is still experimental and required 显式地选择开启.

// vite.config.js
export default {
  plugins: [
    vue({
      reactivityTransform: true
    })
  ]
}

defineProps()Defaults are added via reactive destructuring of :

<script setup lang="ts">
interface Props {
  name: string
  age?: number
}

const { name = '前端开发爱好者', age = 100 } = defineProps<Props>()
</script>

defineEmits()

To get full type inference support when declaring emitsoptions , we can use the defineEmitsAPI, which will automatically be used script setupin

Annotate types for defineEmits()

defineEmits()Annotation Type Direct Recommendation 泛型Form

import type { GlobalTheme } from 'naive-ui'

const emit = defineEmits<{
  (e: 'setThemeColor', val: GlobalTheme): void
}>()

Although the official also recommends 运行时a form of automatic derivation, but I do not recommend it very much

defineExpose()

defineExpose()Compiler macros to explicitly specify the script setupcomponents to be exposed in the component property, so that the parent component 模板refcan obtain the instance of the current component by means of

Annotate types for defineExpose()

defineExpose()Type deduction can directly use the parameter type to automatically deduce

<script setup>
import { ref } from 'vue'

const name = ref<string>('前端开发爱好者')

defineExpose({
  name
})

provide()

provide()Provides a value that can be injected by descendant components

type definition

function provide<T>(key: InjectionKey<T> | string, value: T): void

Annotate the type for provide()

For provide()annotated types, Vue provides an InjectionKeyinterface, which is Symbola and can be used to synchronize the type of injected values ​​between providers and consumers

import type { InjectionKey } from 'vue'

// 建议声明 key (name) 放到公共的文件中
// 这样就可以在 inject 的时候直接导入使用
const name = Symbol() as InjectionKey<string>

provide(name, '前端开发爱好者'// 若提供的是非字符串值会导致错误

The above method is to mark the type by defining the type of the key, and there is another method to directly keyuse 字符串the form to add

provide('name''前端开发爱好者')

inject()

inject()Inject a value supplied by an ancestor component or the entire application

type definition

// 没有默认值
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

Annotate the type for inject()

provide()keyThe type of is provided declaratively (the first form of the provide() type annotation)

inject()You can directly import the declared keyto get the value provided by the parent component

// 由外部导入
const name = Symbol() as InjectionKey<string>

const injectName = inject(name)

If provide()the keydirectly used 字符串form is added, it needs to be declared through the generic parameter

const injectName = inject<string>('name')

template ref

Templates refneed to be created with an explicitly specified 泛型参数and a 初始值 null:

<img ref="el" class="logo" :src="Logo" alt="" />

const el = ref<HTMLImageElement | null>(null)

component ref

Sometimes, you may need to add a template ref to a child component in order to call the methods it exposes

<!-- Child.vue -->
<script setup lang="ts">
const handleLog = () => console.log('前端开发爱好者')

defineExpose({
  open
})
</script>

In order to get MyModalthe type of , we first need to typeofget its type through , and then use the TypeScriptbuilt- in InstanceTypetool type to get its instance type:

<!-- parent.vue -->
<script setup lang="ts">
import Child from './Child.vue'

// 为子组件 ref 声明类型
const child = ref<InstanceType<typeof Child> | null>(null)

// 调用子组件中的方法
const getChildHandleLog = () => {
  child.value?.handleLog()
}
</script>

event handler

Native DOM event annotation type

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

<script setup lang="ts">
function handleChange(event: Event{
  console.log((event.target as HTMLInputElement).value)
}
</script>

- EOF -

Recommended reading   Click on the title to jump

1. The wind and rain of Xidian and Chengdian

2. TikTok officially announced that it will store data on Oracle servers!

3. If the programmer is in jail, will he be arranged to write code?

Pay attention to "programmers' things" and star, don't miss things in the circle

Like and watching is the biggest support ❤️