Skip to content

指令使用过程中 ts 约束值的类型

当我们在使用指令的时候,往往需要传递一些值,那么这些值该如何约束呢?

举个例子

vue
<template>
  <div>
    <div v-my-direct="{ type: 'apple' }"></div>
  </div>
</template>

<script lang="ts" setup>
import { defineDirective } from "vue";

const vMyDirect = defineDirective({
  mounted(el, binding) {
    console.log(binding.value); // { type: 'apple'}
  },
});
</script>

在上面的例子中,我们在指令中使用了 binding.value 来获取传递的值,但是这个值的类型是 any,如果我们想要约束这个值只能是applebananaorange中的一个,否则编译时会报错,已达到类型约束的目的。

解决方法

这里不赘述一些其他的方法,直接给出通用的解决办法

新建指令文件

ts
// src/directives/my-direct.ts
import { DirectiveBinding } from "vue";
// binding请给具体的类型,方便在mounted里面使用
export const myDirect = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    console.log(binding.value);
  },
};

全局注册指令

ts
// src/main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { myDirect } from "./directives/my-direct";

const app = createApp(App);

app.directive("my-direct", myDirect);

app.mount("#app");

新建类型文件

注意

这里我们要全局去扩展 vue 的类型

ts
// src/types/directives.ts
import type { Directive } from "vue";

type MyDirectType = "apple" | "banana" | "orange";

declare module "vue" {
  interface ComponentCustomProperties {
    vMyDirect: Directive<Element, { type: MyDirectType }>;
  }
}

修改 tsconfig.json

json
{
  "compilerOptions": {
    "strict": true, // 严格模式 注意这里开启后,ts会进行严格的类型检查,意味着你必须要去处理一些类型,如any
    "typeRoots": ["./node_modules/@types", "./src/types"]
  }
}

使用指令

vue
<template>
  <div>
    <!-- 正确 -->
    <div v-my-direct="{ type: 'apple' }"></div>
    <!-- 错误 -->
    <div v-my-direct="{ type: 'pear' }"></div>
  </div>
</template>

所有代码

vue
<template>
  <div>
    <div v-my-direct="{ type: 'apple' }"></div>
  </div>
</template>
ts
import type { Directive } from "vue";

export type MyDirectType = "apple" | "banana" | "orange";

declare module "vue" {
  interface ComponentCustomProperties {
    vMyDirect: Directive<Element, { type: MyDirectType }>;
  }
}
ts
import { DirectiveBinding } from "vue";
import type { MyDirectType } from "../types/directives";

export const myDirect = {
  mounted(el: HTMLElement, binding: DirectiveBinding<{ type: MyDirectType }>) {
    console.log(binding.value.type); // 类型是MyDirectType,而且开发工具会有相关提示
  },
};
ts
import { createApp } from "vue";
import App from "./App.vue";
import { myDirect } from "./directives/my-direct";

const app = createApp(App);

app.directive("my-direct", myDirect);
app.mount("#app");
json
{
  "compilerOptions": {
    "strict": true, // 严格模式 注意这里开启后,ts会进行严格的类型检查,意味着你必须要去处理一些类型,如any
    "typeRoots": ["./node_modules/@types", "./src/types"]
  }
}

发现光 追随光 成为光 超越光