有没有一种方法可以强制使用Typescript中的泛型使类型动态相同?

时间:2019-01-10 17:58:22

标签: typescript

我正在尝试创建一个用于类中事件处理的模式,它涉及一个为类快速设置事件的函数。它需要一个函数,该函数可以接受任意数量的参数并返回void和具有这些函数数组的对象的键。我想使用泛型来确保传递的函数的参数与使用键获取的数组中的函数类型相同。因此,如果传递的T为()=> void,则this.eventListeners [key]的类型也应为T。

也许对于Typescript来说这是不可能的。在C ++中,我会通过模板传递密钥以确保类型安全,这可以在Typescript中完成吗?

> pd.concat({x:data_df.mul(mask_df[x],0).sum() for x in mask_df}).unstack()

    a  b  c
g1  2  2  5
g2  2  3  2

编辑:因此从这个github问题来看,Typescript即将完成,因此绝对有一种方法可以实现我想要的。我们只需要弄清楚如何做。 https://github.com/Microsoft/TypeScript/issues/14833

编辑:我已经足够创建必要的类型,但是我不确定如何编写函数:

type TonActionListener = (_:Action) => void;                                                                                                                                                                                                                                  
type TonDisconnectListener = () => void;                                                                                                                                                                                                                                      
type IeventListeners = {                                                                                                                                                                                                                                                      
  onAction: Array<TonActionListener>;                                                                                                                                                                                                                                         
  onDisconnect: Array<TonDisconnectListener>;                                                                                                                                                                                                                                 
} 

export default class ControllerConnection {  
  protected eventListeners = {                                                                                                                                                                                                                                                
    onAction: [],                                                                                                                                                                                                                                                             
    onDisconnect: [],                                                                                                                                                                                                                                                         
  } as IeventListeners;
  // add an event listener by key and return a callback to remove that event listener.                                                                                                                                                                                        
  protected addEventListener<T>(key: (keyof IeventListeners), eventListener:T): (() => void) {                                                                                                                                                                                
    (this.eventListeners[key] as Array<T>).push(eventListener);                                                                                                                                                                                                               
    return () => void ((this.eventListeners[key] as Array<T>) = (this.eventListeners[key] as Array<T>).filter((l:T):boolean => l != eventListener));                                                                                                                          
  }                                                                                                                                                                                                                                                                           
  onAction:any = (onActionListener: ((_:Action) => void)) => 
  this.addEventListener('onAction', onActionListener);                                                                                                                                                             
  onDisconnect:any = (onDisconnectListener: (() => void)) => 
  this.addEventListener('onDisconnect', onDisconnectListener);
}

编辑:我更近了……我只需要获取addListener来接受Tk很好地被调用者传递。而不是立即定义。我更新了上面的代码。

1 个答案:

答案 0 :(得分:0)

这不是完美的,但我接近了。类型检查有效,但是您需要两次指定类型,它不是干燥的。幸运的是,由于可以进行类型检查,因此可以很好地检查两种类型是否相同。

type IListener = {
    [ key in (keyof typeof MyClass.prototype.listeners) ]: typeof MyClass.prototype.listeners[key][0];
}

class MyClass {
    listeners = {
        onAction: [] as Array<(_: string) => void>,
        onDisconnect: [] as Array<() => void>,
        //etc...
    };

    addListener = <Tk extends keyof IListener, Tl extends IListener[Tk]>(listener: Tl, key: Tk) => {
        (this.listeners[key] as Array<Tl>).push(listener);
        return () => {
            (this.listeners[key] as Array<Tl>) = (this.listeners[key] as Array<Tl>).filter((l:Tl):boolean => l !== listener);
        };
    };

    onAction = (listener: IListener["onAction"]):VoidOp => this.addListener(listener, "onAction");
    onDisconnect = (listener: IListener["onDisconnect"]):VoidOp => this.addListener(listener, "onDisconnect");
}

最后我还是使用了另一种方法。我有一个操场,我所有的想法都在下面的代码中。如果您好奇,可以查看一下:

https://typescript-play.js.org/#code/C4TwDgpgBAag9gSwCYHkxQLxQBQEpMB8UAbokgNwBQ1A9DVCgAoAqAkigHJQCMUd1oSFFYAZBAGdgEAHYQATpigBvSlDVQA2lADWEEFATScukHABmUQRHNQAsiADCAGwCG48QDowcuMF-gIDycJKVk5cXwAXQAuSwCbe2c3T29ff0ggkJl5cQ0TSI0ABkiqAF9qAGNXdztHavFlVXVgyWzwxRV1Lqg4aQBBCuAEXtiNSKg3KD65ORcQAB5sAH1YyTlDAHN8DCJSZAIAGibunukAEQkK3tlB0fHJ6dmFvEISMkPj7roIYAqPf8+pSonxcSCQYlaYUU82Y2igEAAHqEkA0TDZRFkwgcoMwnPCkTIUcIIaF5BpYZECNgWqS5LFcdiTPTtNsiJ0TjhgAALCSZSE5PJ6e4NR5zGFOAi4LwAV3EXOpmPkuCoHKgch+0rkRheO0aqq62G5vJpbVy+QmIpmYtxksUhp5nhNYTNQotUytCxtUrMCCcUjk2Gp0VxuGiACM4HAnBAXEZdXiAIQYLBOpUqjlAwHArq9AZDXp21N04mKuQaABEucGw2k5ciofgyDQryNnlB4NLCv5cmxlf61d65eVn16F3EV2kN2AhdLsQx3Yro8u1wggzrDbIzd1rY87ZJbS7tN7S-HK7Xw-KlDoUAAohwzgwWOwuLx+Ff6Ew2JwoAAmPg0AQAhLbsGiwdk1D7PMa3LUY1k2EpPj7McJynGDNAQy8qmSWokncP9wPhYgZGAG8AFsEGAf1FFkAB3W8iOkEjyMo+R5nnWlxCpYcczjSwHQ8CAGKYij-Q8Xoyloeg7wfT9n1-f9qEoaNp1IxxqIgOjEnqH88CoVSHDE6RsAAcirfNpGM7FsDWaI4OkLZXgncQo0CJw4A2azgDkXBhyUn4oH0+p1M0upkl06hAuSQyoN6QMXAHaRbK8zZQzeZBHN6ZzoyCdyTK5CAnDc4yfL00L3EM5Cz2AQNUr2JAMukLLXNy4z8sKuBit8685TgaUnHq+QfDkDxKEi8qTxQ1dquweLzKS9Z7NqsgGqanKPNagqipKySoAAWn2g7DuoREwDgORpywmobyEsiRNY5h8WRBolE0OFDCgABpPpCpiCZpBAMYoFKbEvsKx7CVRPQbAerA0QsZg2SaItxFiWwXDAeZQacKzsH+Xc5A2FGcQ0LH61eOrcDGIgsFoux0fCpoaAAKiZ44magABlYAXHOhonU2Sw4D+wjiJG9R2YAATAHmXFIkXGL46BBOIwWoCdQWxbUSXpdmOWiygMxpWkBLVbDaAKhcQqIHqmj8qMWM+IkeXpydiBmKkJBNagSX1WATUjAtwqw3iuE-DVN24CIxXnbV0s2YAtRekx8HpCJLGiGwZXGNiD7sSLWJcf+HnCfpEmyd1CmC9ZNL6oIpzpxpO0d2RjwNh+TOhPwAAfLv0KlcRggqCBwq6euDFTxFFBpIIZA2bl0zUaewFleUi249Rff9nBq+n8QwEH4fDCQRF18vNRmdZ8Xb2YhoHaz6cw8tvEKk1dVGKcfRxGlMNx3WM36pbmzKAUsZZy3vtHcBYc3YUS9trUBEwCa33+ggjY0pSLEQaOqAAjtKBA6p6pmDOhAoSsCE7wmYsnRET1PrfQlDge+OdsR42LkTZgZd8AEUIQobAY99Y2GbqWTwbdqr327r3MYHDPiL07MwxBuBARNHKKUIAA