根据接口键入check class reference

时间:2015-04-02 14:33:21

标签: typescript

我想将类引用传递给将创建并返回该类实例的函数。但是,我想根据它实现的接口类型检查传入的类。

accepted answer to 'How does typescript interfaces with construct signatures work?'描述了一种依赖于构造函数签名的结构类型检查的方法。当然,这个问题特定于构造函数签名,所以也许我正在咆哮错误的树,因为在我的例子中:

  1. 实现IHappyController的类不共享相同的构造函数签名。

  2. 当不相关接口中的构造函数匹配时,很容易产生误报。

    interface IHappyController
    {
      name:string;
    }
    
    interface IHappyControllerConstructable
    {
      // This constructor is compatible with JoyfulController
      new ( name:String, joyfulSong:string, joyfulColor:string ):IHappyController;
    
      // This constructor is compatible with DelightfulController
      //new ( name:String, time:Date ):IHappyController;
    }
    
    interface ISadController
    {
      name:string;
      reason:string;
    }
    
    interface ISadControllerConstructable
    {
      // This constructor is compatible with DismalController, signature is same as DelightfulController
      new ( name:String, time:Date ):ISadController;
    }
    
    class JoyfulController implements IHappyController
    {
      constructor( public name:string, joyfulSong:string, joyfulColor:string )
      {
    
      }
    }
    
    class DelightfulController implements IHappyController
    {
      constructor( public name:string, time:Date )
      {
    
      }
    }
    
    class DismalController implements ISadController
    {
      reason:string;
    
      constructor( public name:string, time:Date )
      {
    
      }
    }
    
    // happyMaker should return an instance of the passed class, but only if the instance implements IHappyController
    var happyMaker = ( clazz:IHappyControllerConstructable ):IHappyController => {
      var instance:IHappyController = ServiceLocator.getByClass( clazz );
      return instance;
    }
    
    happyMaker(JoyfulController);       // Expect Success, it implements IHappyController
    happyMaker(DelightfulController);   // Expect Success, it implements IHappyController
    happyMaker(DismalController);       // Expect Error, it implements ISadController
    
  3. 更简单的解决方案?

    我猜(希望)有一个更简单的解决方案,根本不依赖于I*Constructable接口。但是happyMaker()的方法签名应该是什么?

    interface IHappyController
    {
      name:string;
    }
    
    interface ISadController
    {
      name:string;
      reason:string;
    }
    
    class JoyfulController implements IHappyController
    {
      constructor( public name:string, joyfulSong:string, joyfulColor:string )
      {
    
      }
    }
    
    class DelightfulController implements IHappyController
    {
      constructor( public name:string, time:Date )
      {
    
      }
    }
    
    class DismalController implements ISadController
    {
      reason:string;
    
      constructor( public name:string, time:Date )
      {
    
      }
    }
    
    // happyMaker should return an instance of the passed class, but only if the instance implements IHappyController
    var happyMaker = ( clazz:/* WHAT GOES HERE? */ ):IHappyController => {
      var instance:IHappyController = ServiceLocator.getByClass( clazz );
      return instance;
    }
    
    happyMaker(JoyfulController);       // Expect Success, it implements IHappyController
    happyMaker(DelightfulController);   // Expect Success, it implements IHappyController
    happyMaker(DismalController);       // Expect Error, it implements ISadController
    

1 个答案:

答案 0 :(得分:2)

所写的示例无效,因为ISadControllerIHappyController的子类型而TypeScript使用结构类型,因此对IHappyController有效的任何内容都将有效与ISadController

有关

如果您调整IHappyController以使其不是ISadController的超类型,则可以执行此操作:

interface IHappyController {
  happyName: string;
}

interface ISadController {
  name:string;
  reason:string;
}

class JoyfulController implements IHappyController {
  constructor(public happyName:string, joyfulSong:string, joyfulColor:string) { }
}

class DelightfulController implements IHappyController {
  constructor(public happyName:string, time:Date) { }
}

class DismalController implements ISadController {
  reason:string;
  constructor(public name:string, time:Date) { }
}

declare var ServiceLocator;
var happyMaker = <T extends IHappyController>( clazz: { new(...args: any[]): T } ): T => {
  var instance = ServiceLocator.getByClass( clazz );
  return <T>instance;
}

happyMaker(JoyfulController); // OK
happyMaker(DelightfulController); // OK
happyMaker(DismalController); // Error