在Typescript中混合使用接口

时间:2014-09-02 03:00:18

标签: interface typescript

我有一个包含80多个方法的类,每个方法都接受一个包含一些已定义接口的对象。

class Stuff {
   /* many more */
   getAccount(req: IAccount, callback: ICallback) {
      return this._call('getAccount', req, callback);
   }

   getIds(req: IIDs, callback: ICallback) {
      return this._call('getIds', req, callback);
   }
   /* many more */
}

漂亮&无聊'这些东西,因为它只是映射到底层_call方法,并使每个方法的类型安全。

但有时候这些req param对象是由2个或更多接口组成的,而不是每次都创建另一个接口,而不是'#34;尴尬",就像这样: / p>

export interface ILoled extends IAccount {
   loled: boolean;
}

export interface IRofloled extends ILoled {
   rofled: boolean;
}

class Stuff {
  getLols(req: ILoled){
  }

  getRofls(req: IRofloled){
  }
}

有什么方法可以把它作为"内联"在方法参数列表中混合接口?喜欢(显然不能工作):

class Stuff {
  getMoreStuff(req: <{} extends IAccount, ITime>) {
  }
}

3 个答案:

答案 0 :(得分:11)

是的,你可以as of Typescript 1.6。名为 交叉点类型 ,请使用&运算符组合类型。

function extend<T, U>(first: T, second: U): T & U {
  let result = <T & U> {};
  for (let id in first) {
    result[id] = first[id];
  }

  for (let id in second) {
    if (!result.hasOwnProperty(id)) {
      result[id] = second[id];
    }
  }
  return result;
}

var x = extend({ a: "hello" }, { b: 42 });
x.a; // works
x.b; // works 

答案 1 :(得分:2)

  

有什么方法可以把它作为&#34;内联&#34;在方法参数列表

中混合接口

没有。您不能扩展内联接口

答案 2 :(得分:0)

我不确定这是否有帮助,但是您是否知道使用by关键字的Kotlin接口实现委派?
在Kotlin中,您基本上可以创建一个实现一个接口的类,并使用它为另一个类委派同一接口的实现,例如:

interface Abc {
    val foo: Int
}

class HelloAbc : Abc {
    val foo = 5
}

class MyClass : Abc by HelloAbc() {
    val bar = "Hello world"
}

上面的代码创建了一个名为Abc的接口,一个实现该接口的类HelloAbc和一个另外的类MyClass,该类使用HelloAbc来实现{{1 }}。

我刚刚意识到它在TypeScript中也很有用,我可以提出一种类型安全的mixin实现,如下:

Abc

下面的演示代码说明了如何使用此技术委派接口实现:

type UnionToIntersectionUnchecked<T> =
    (T extends any
        ? (k: T) => void
        : never
        ) extends ((k: infer I) => void)
            ? I
            : never

type IsUnion<T> = [T] extends [UnionToIntersectionUnchecked<T>] ? false : true

type UnionToIntersection<T> =
    IsUnion<T> extends true
        ? UnionToIntersectionUnchecked<T>
        : T

function deepCopy<T, U>(target: T, source: U): T & U {

    const chain = []

    for (let proto = source; source !== Object.prototype; source = Object.getPrototypeOf(source))
        chain.unshift(proto)

    for (const proto of chain)
        Object.defineProperties(target, Object.getOwnPropertyDescriptors(proto))

    return target as T & U
}

function mixin<
    TBase extends object,
    T extends object[]
    >(
        baseClass: { new (...args: any[]): TBase },
        ...objects: T
    ): { new (): TBase & UnionToIntersection<T[number]> } {

    const proto = Object.assign(Object.create(baseClass.prototype), ...objects)

    const ctor = (function(this: TBase, ...args: any[]) {

        const thisProto = Object.getPrototypeOf(this)
        const instance = new baseClass(...args)

        Object.setPrototypeOf(instance, deepCopy(proto, thisProto))

        return instance
    }) as any

    Object.setPrototypeOf(ctor, baseClass)

    return ctor
}

您甚至可以在playground上对其进行测试。

您将要避免在对性能有要求的代码中避免这种情况,因为创建所有这些原型可能会很昂贵,但是我不希望它对整体产生太大影响。