使用mixin的打字稿钻石

时间:2017-11-18 05:16:49

标签: typescript mixins

我有一套可以“天真地”的课程。表示为钻石:

  OneBase
 /      \
OneDer   TwoBase
 \      /
  TwoDer

[注意 - 由于@mitch评论已更改名称。]

事实上,OneTwo是" base"类,除OneDerTwoDer之外还有几个不同的类,它们使用相同的模式从它们派生。假设(OneBase,TwoBase)位于模块base中,(OneDer, TwoDer)位于模块derived中。

同样OneBase包含一个Part个结构,其中包含TwoBase个实例;在OneDer中,等效结构应包含TwoDer实例。

我将TwoBase转换为mixin,以下代码编译:

模块base

export type Constructor<T> = new(...args: any[]) => T

export class One {
  p: Part
  constructor (readonly a: number) {}
}

export class TwoPre extends One {
  constructor (readonly a: number, readonly c: M[]) {
    super(a)
  }
}
export function TwoMix<
    T extends Constructor<TwoPre>> (Base: T): Constructor<TwoPre> {
  class Two extends Base {

  }
  return Two
}
export const Two = TwoMix(TwoPre)
export interface Part {
  u: typeof Two
}

模块derived

import { Part, One, TwoMix } from './base'

export class OneDer extends One {
  p: Part
}

export class TwoDerPre extends OneDer {
  constructor (readonly a: number, readonly c: M[]) {
    super(a)
  }
}

export const TwoDer = TwoMix(TwoDerPre)

请注意TwoPreTwoDerPre是必要的,因为&#34;天真&#34; Two具有与One不同的构造函数签名,mixin函数无法定义 构造函数。这有点痛苦,因为它不必要地增加了原型链 - 所以变通方法很受欢迎。除此之外,mixin 确实强制执行我想要的方法解析顺序。

当我尝试强制PartDerPart之间的差异时,真正的问题出现了;此版本的模块derived无法编译:

import { Part, One, TwoMix } from './base'

export class OneDer extends One {
  p: PartDer
}

export class TwoDerPre extends OneDer {
  constructor (readonly a: number, readonly c: M[]) {
    super(a)
  }
}

export const TwoDer = TwoMix(TwoDerPre)
export interface PartDer extends Part {
  u: typeof TwoDer
}

我收到错误: src/derived.ts(13,14): error TS7022: 'TwoDer' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. src/derived.ts(15,3): error TS2502: 'u' is referenced directly or indirectly in its own type annotation.

我想知道为什么编译器抱怨这个循环时它没有在base中抱怨它,我能做些什么呢?

注意这是我能想到的表达问题的最短路径。当然,TwoDer实际上不仅仅是mixin的实例化,因此derived末尾的代码看起来更像是:

export class TwoDer extends TwoMix(TwoDerPre) {

}
export interface PartDer extends Part {
  u: TwoDer
}

使用此版本,我会遇到稍微不同的错误: src/derived.ts(17,6): error TS2304: Cannot find name 'TwoDer'. src/derived.ts(17,6): error TS4033: Property 'u' of exported interface has or is using private name 'TwoDer'. 如果我将PartDer转换为使用typeof TwoDer,我会收到原始错误:

export interface PartDer extends Part {
  u: typeof TwoDer
}

1 个答案:

答案 0 :(得分:1)

我无法理解你想要做的事情,但TypeScript在这里丢失了一些类型信息:

export const TwoDer = TwoMix(TwoDerPre)

这导致了效果。您可以通过添加一些类型信息来解决此特定问题:

export const TwoDer: Constructor<TwoPre> = TwoMix(TwoDerPre)

这清除了'u' is referenced directly or indirectly in its own type annotation.混淆的问题。我不知道它是否能让一切对你有用。