typescript - 我可以指定一个接口(interface)将共享另一个接口(interface)的 key 吗?

标签 typescript

我有两个接口(interface),我想共享相同的键,但不共享相同的值。假设第一个接口(interface) (Thing) 来自外部库,第二个接口(interface) (ThingOptions) 在我的项目中。

interface Thing {
  foo(value: number): void;
  bar(value: string): void;
  someOtherKey: null;
}

interface ThingOptions {
  foo: number;
  bar: string;
}

有没有办法断言 ThingOptions 的键是 Thing 的键的子集?

最佳答案

有几种方法可以对此进行一些编译时检查,但我认为所有这些方法都需要稍微重复 ThingOptions姓名。

一种方法是制作 KeysFrom<T, U>它采用类型 T和候选类型 U ,仅与 U 兼容如果 U 的键是 T 的子集(这意味着 T 可以有 U 没有的键,但是 U 不能有 T 没有的键):

type KeysFrom<T, U> = { [K in keyof U]: K extends keyof T ? U[K] : never }

所以 KeysFrom<{a: string}, {a: number}>就变成了{a: number} ,这{a: number}延伸。但是KeysFrom<{a: string}, {b: number}变成 {b: never} ,这{b: number}不延伸。然后你声明 ThingOptions延伸KeysFrom<Thing, ThingOptions> .这是一个递归约束。让我们看看:

interface ThingOptions extends KeysFrom<Thing, ThingOptions> {
    foo: number;
    bar: string;
}

行得通。

interface BadThingOptions extends KeysFrom<Thing, BadThingOptions> { // error!
//        ~~~~~~~~~~~~~~~ <-- properties of type "bap" are incompatible
    foo: number;
    bap: string;
}

而且编译失败,正如您可能希望的那样。


您可以做的另一件非递归的事情是将检查移动到它自己的行:

type KeysAreSubset<
    T,
    U extends { [K in keyof U]: K extends keyof T ? U[K] : never }
> = true;

在这里,KeysAreSubset<T, U>评估为 true总是,但是U现在限制为 KeysFrom<T, U> .如果你使用 KeysAreSubset<ThingOptions, U>坏了U ,你会得到一个错误:

interface ThingOptions {
    foo: number;
    bar: string;
}

type ThingOptionsIsOkay = KeysAreSubset<Thing, ThingOptions>;

interface BadThingOptions { 
    foo: number;
    bap: string;
}

type BadThingOptionsIsNotOkay = KeysAreSubset<Thing, BadThingOptions>; // error!
//  Types of property 'bap' are incompatible. -----> ~~~~~~~~~~~~~~~

这两个都有效,但它们都需要您重写名称 ThingOptions ,它们都需要您跳过一些障碍才能正确使用。不过,它可能适用于您的用例。祝你好运!

Link to code

关于typescript - 我可以指定一个接口(interface)将共享另一个接口(interface)的 key 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58438027/

相关文章:

javascript - 如何使用单个 Prop 修复括号中的 prettier 和 tslint 错误?

typescript 错误 "Object is of type ' 未知'。”

typescript - 自动从父类导入对象

typescript - 如何 "import"TypeScript 定义文件中的命名空间

Angular2(最终版本)和 Firebase 身份验证不是持久的

Angular 8 在初始化之前无法访问 'PlanningModule'

javascript - Ava 单元测试因 TypeScript 失败 ("SyntaxError: Unexpected identifier")

javascript - expose-loader 不会公开对公开对象的修改

javascript - 如何在 Angular 4 Material 的 Stepper 中提交表单

Angular 8发出多个http请求并合并所有结果