首页 > 解决方案 > Vue:具有可选属性的类型化道具接口

问题描述

我创建了一个我希望在我的所有 Vue 实例上都可用的方法,我可以在发生错误时调用它并呈现特定的错误组件。像vue-error-page这样的东西。我正在使用打字稿,现在我想确保使用正确的类型化道具调用组件,如果传递的道具中有错字,则会出现编译时错误。

目前我在 shims.d.ts 文件中有这个:

import Vue, {VueConstructor} from 'vue'

declare module 'vue/types/vue' {
    interface Vue {
        $error (component:VueConstructor<Vue>, props:unknown) : void;
    }
}

这允许我像这样调用我的插件。传递的对象与 ErrorPage 组件的 props 定义匹配:

import Vue from "vue";
import ErrorPage from "./views/ErrorPage.vue";
export default Vue.extend({
  mounted() {
    this.$error(ErrorPage, { errorTitle: "Could not load the page" });
  }
});

虽然这是有效的,但如果道具与组件的预期不匹配,我想得到一个编译时错误。

所以我想我会像这样改变 shims.d.ts:

declare module 'vue/types/vue' {
    interface Vue {
        $error<Props> (component:ExtendedVue<Vue, unknown, unknown, unknown, Props>, props:Props) : void;
    }
}

现在,当 props 对象不匹配时,我会收到编译时错误。但是,当我不传入可选属性时,也会出现错误。我的 ErrorPage 组件如下所示:

import Vue from "vue";
export default Vue.extend({
  name: "Error",
  props: {
    errorTitle: {
      type: String,
      required: true,
      default: "Error"
    },
    errorDescription: {
      type: String,
      required: false,
      default:
        "Something went wrong."
    }
  }
});

如果我没有通过 errorDescription,我不应该得到错误。这就是我想要完成的。我希望能够做以下事情:

// Should compile and does right now.
this.$error(ErrorPage, {errorTitle: "Oops", errorDescription: "Something went wrong" });

// Should compile and does not right now. Fails with error:
// Argument of type '{ errorTitle: string; }' is not assignable to parameter of type '{ errorTitle: string; errorDescription: string; }'.
// Property 'errorDescription' is missing in type '{ errorTitle: string; }' but required in type '{ errorTitle: string; errorDescription: string; }'."
this.$error(ErrorPage, {errorTitle: "Oops" });

TL;DR 问题:

如何使用道具作为参数使我的方法调用类型安全,同时能够省略可选属性?我可以同时更改 shims.d.ts 和 ErrorPage 组件。

标签: typescriptvue.js

解决方案


即使您将其标记为不需要,打字稿类型仍然是String,因此您需要在调用方法时传递它。

你可以试试这个(我没有测试过它是否有效)

使用别名声明可以为空的类型

type ErrorDescriptionType = String | undefined | null

然后将其作为类型传递给errorDescription

errorDescription: {
  type: Object as () => ErrorDescriptionType,
}

推荐阅读