【问题标题】:Get generic interface extension获取通用接口扩展
【发布时间】:2018-04-22 14:24:00
【问题描述】:

考虑以下接口:

interface A {
   name: string;
   value: number;
   sub: {
       query: number[]
   },
   old: number;
}

interface B {
   name: string;
   value: string;
   sub: {
       query: string[]
   },
   new: boolean;
}

我正在寻找获取接口/类型的通用解决方案:

interface C extends B, A {
}

C 就像接口 D:

interface D {
   name: string;
   value: string;
   sub: {
       query: string[]
   },
   old: number;
   new: boolean;
}

所以我可以有一个函数:

function merge<T, U>(t: T, u: U): interface C extends T, U {
  // Merge objects
  // ...
  return obj;
}

它不一定是一个接口。类型也会这样做(我认为)。

A &amp; B 类型不起作用,因为那时我有一个交叉点(例如,value 将是 number &amp; string 类型)。

【问题讨论】:

  • 除了 Intersection 类型之外,还有另一种高级类型 - Union Type,它可以接受数字或字符串的值。更多文档在这里 - typescriptlang.org/docs/handbook/advanced-types.html
  • A | B union 不会做你想做的事吗?
  • 没有。一个 | B 不一样。

标签: typescript types set-theory


【解决方案1】:

我使用这种MergeReplace 类型来更准确地输入诸如Object.assign({}, T, S) 之类的内容:

type MergeReplace<T, S> = Omit<T, keyof T & keyof S> & S;
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

如果你使用的是 Exclude 可以这样定义:

type Project<K extends string, T> = (T & {[x: string]: never})[K];
type Delete<T extends string, U extends string> = ({[P in T]: P} & {[P in U]: never});
type Exclude<T extends string, U extends string> = Project<T, Delete<T,U>>;

TypeScript playground with examples

注意MergeReplace 是右偏的,所以如果TS 共享一个属性但类型不同,则选择S 中的类型。

查看this TypeScript issue了解更多信息。

【讨论】:

  • 谢谢。这是正确的方向。但它不支持嵌套对象。
  • 不,它不会,它只会取最右边的那个。我认为支持合并嵌套对象类型而不为不同类型的属性(如 value)创建交集类型会很棘手,但也许有一个聪明的解决方案。
【解决方案2】:

我想我明白了:

type MergeRightBiased<TLeft, TRight> =
  TLeft extends any[] ? TRight :
    TRight extends any[] ? TRight :
      TLeft extends object ?
        TRight extends object ? {
          // All properties of Left and Right, recursive
          [P in keyof TLeft & keyof TRight]: MergeRightBiased<TLeft[P], TRight[P]>
        } & {
          // All properties of Left not in Right
          [P in Exclude<keyof TLeft, keyof TRight>]: TLeft[P];
        } & {
          // All properties of Right not in Left
          [P in Exclude<keyof TRight, keyof TLeft>]: TRight[P]
        }
          // Prefer Right
          : TRight
        : TRight;

感谢@Oblosys 的帮助!

【讨论】:

  • 啊,是的,这是一个有趣的解决方案!如果某物只是右侧的对象(例如Merge&lt;{o:42},{o:{p:1}}&gt;),这有点狡猾,但T 上的额外条件可以解决这个问题。我希望[P in Exclude&lt;keyof U, keyof T&gt;]: U[P] 更对称,而不是U,但我想这是由于正确的偏见。 (顺便说一句,@username pings 仅在 cmets 中有效)
猜你喜欢
  • 1970-01-01
  • 2020-06-09
  • 2020-04-09
  • 1970-01-01
  • 1970-01-01
  • 2018-03-29
  • 2016-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多