【问题标题】:Express interface containing common properties of two tree-like objects in TypeScript包含 TypeScript 中两个树状对象的公共属性的 Express 接口
【发布时间】:2020-12-13 23:10:03
【问题描述】:

假设我们有两个接口AB

interface A {
   width: number;
   height: number;
   label: {
       text: string;
   };
   navigator: {
       min: number;
       max: number;
   }
}

interface B {
   width: number;
   height: number;
   label: {
       text: string;
       formatter: (text: string) => string;
   };
   radius: number;
}

我可以像这样手动指定所需的通用形状:

interface AB {   // ????????
   width: number;
   height: number;
   label: {
       text: string;
   };
}

但理想情况下,我希望类型系统能够像这样自动计算出形状:

type AB = A & B; // ????????

显然,type AB 不具有interface AB 的预期形状。

有什么想法吗?

编辑:一个示例用例:

const defaultTheme: AB = {
    common: { // default values for properties common to A and B
        width: 800,
        height: 400,
        label: {
            text: 'Title'
        }
    },
    A: { // missing defaults will come from `common`
        navigator: {
           min: 0,
           max: 1
        }
    },
    B: { // missing defaults will come from `common`
       label: {
           formatter: (text: string) => '$' + text
       },
       radius: 50
    }
};

// The user would configure a component in a declarative fashion:
const userConfig = {
    theme: defaultTheme,
    items: [{
        type: 'A',
        height: 600,
        navigator: {
            min: 0.5
        }
    }, {
        type: 'B',
        label: {
            text: 'My Custom Title'
        }
    }]
}

因此用户未明确指定的项目属性将来自默认主题。

【问题讨论】:

  • 递归执行此操作 (label) 将非常棘手。如果只是这两个,交叉类型不工作吗?您可以使用类型的公共部分而不区分它们,但是如果您区分它们(例如,使用警卫),则每个完整类型都可用。关闭这种可能性的类型 AB 的用例是什么?
  • 我必须删除 cmets 以使其适合 SO 注释,因此:(1) = 使用公共部分。 (2) 当且仅当您需要使用 A 或 B 的特定部分时,一旦确定了您所拥有的,您就可以使用。 (3) 这是一个 A。 (4)。这是一个 B。
  • @T.J.Crowder 谢谢。例如,如果库用户想要指定应用于项目数组中所有对象的通用属性,而不必将这些属性合并到每个项目的配置中。如果可以使用类型系统来指导用户哪些属性对每种项目类型有效,我会很好。
  • @T.J.Crowder 哈哈,这很公平,我认为这可能是答案,但我有希望 :) 感谢您的回复!

标签: typescript types interface intersection


【解决方案1】:

您在评论中给出了一个示例用法,解释了为什么 A & B 不能满足您的要求:

例如,如果库用户想要指定应用于项目数组中所有对象的通用属性,而不必将这些属性合并到每个项目的配置中。

这是有道理的。这并不是关于如何从ABAB 的真正答案,但FWIW 我通常会从另一个方向解决这个问题:定义AB,然后使用extends 创建@987654327 @ 和B,像这样:

interface AB {
   width: number;
   height: number;
   label: {
       text: string;
   };
}

interface A extends AB {
   navigator: {
       min: number;
       max: number;
   }
}

interface B extends AB {
   label: {
       text: string;
       formatter: (text: string) => string;
   };
}

我认为尝试从 AB 开始并只保留公共部分,特别是递归(对于 label),将非常复杂......

【讨论】:

    猜你喜欢
    • 2021-10-30
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多