【问题标题】:Interface A incorrectly extends interface B接口 A 错误地扩展了接口 B
【发布时间】:2019-10-14 05:00:27
【问题描述】:

给定这个界面:

interface Props extends React.HTMLAttributes<HTMLDivElement> {
  compLevel: string;
  property: Property;
  comps: Property[];
}

我在使用 property 属性时遇到了困难,因为它已经以 property?: string; 的形式存在于 HTMLAttributes 上:

接口“道具”错误地扩展了接口 'HTML 属性'。财产“财产”的类型是 不相容。 类型“SerializedObject”不可分配给类型“字符串”。

重命名属性是可行的,但我不想这样做。推荐的扩展/方法使用接口是什么,这样我就不需要在我的Props 上重新定义className

【问题讨论】:

    标签: reactjs typescript


    【解决方案1】:

    你打算如何处理Props?您可能不应该在需要 React.HTMLAttributes&lt;HTMLDivElement&gt; 的地方使用它。如前所述,并将代码视为complete 示例,我可能会这样定义Props

    // SimpleSpread<L, R> is a simplified version of what happens when you
    // do an object spread like {...left, ...right} where left is of type L and
    // right is of type R.  It is the type R, with any properties on L that
    // don't exist in R.  (It doesn't work if a key in L is an optional property in
    // R, which is why this is simplified)
    type SimpleSpread<L, R> = R & Pick<L, Exclude<keyof L, keyof R>>;
    
    // Define the props you want to spread into React.HTMLAttributes<HTMLDivElement>
    interface PropsExtra {
      compLevel: string;
      property: Property;
      comps: Property[];
    }
    
    // Define Props
    interface Props
      extends SimpleSpread<React.HTMLAttributes<HTMLDivElement>, PropsExtra> {}
    

    这通过将Props 视为PropsExtra 仅使用来自React.HTMLAttributes&lt;HTMLDivElement&gt; 的那些不出现PropsExtra 中的属性来工作。所以这最终会覆盖 property 属性,而不是扩展它。

    现在没有错误了。


    请注意,以下将是一个错误:

    declare function acceptAttributes(attrs: React.HTMLAttributes<HTMLDivElement>);
    declare const p: Props;
    acceptAttributes(p); // error! p is not a React.HTMLAttributes<HTMLDivElement>
    

    由于property 属性的类型不同(呵呵),Props 类型的值不再是有效的React.HTMLAttributes&lt;HTMLDivElement&gt; 值。任何期望后者的东西都不会接受前者。然后,您可以更改此类函数的预期参数类型,这可能会向外级联,直到此更改涉及的代码库超出您的预期。

    所以这真的取决于你的用例是否适合你。祝你好运!

    【讨论】:

      【解决方案2】:

      由于 'property' 的属性已经存在于 HTMLAttribute 上,我可以看到三种前进的方式:

      1. 将属性重命名为不与现有属性重叠的另一个更精确的术语(例如 propsProperty)
      2. 如果值在某种程度上相似,则可以将属性转换为 SerializedObject 以匹配类型签名
      3. 将属性重命名为_property,并将接口的getter和setter设置为从_property而不是property。 (这个还没测试过)

      【讨论】: