I am trying to write a type definition for flummox but I don't fully understand how I am supposed to write it.
The gist is that we are supposed to subclass Store, Actions and Flummox classes and pass them to functions.
Here's a code example with the actions:
import { Flummox, Actions, Store } from 'flummox';
class MessageActions extends Actions {
newMessage(content: string) {
return content;
}
}
class MessageStore extends Store {
constructor(flux: Flummox) {
super();
const messageActions: MessageActions = flux.getActions('messages'); // error here
this.register(messageActions.newMessage, this.handleNewMessage);
}
}
class Flux extends Flummox {
constructor() {
super();
this.createActions('messages', MessageActions);
this.createStore('messages', MessageStore, this); //error here
}
}
And the definition I started:
/// <reference path="eventemitter3.d.ts"/>
declare module "flummox" {
type ActionId = string;
class Store {
register(action: ActionId | Function, handler: Function): void;
}
class Actions {
}
class Flummox extends EventEmitter3.EventEmitter.EventEmitter3 {
createActions(key: string, actions: Actions, constructorArgs?: any | any[]): Actions;
getActions(key: string): Actions;
removeActions(key: string): Actions;
createStore(key: string, store: Store, constructorArgs?: any | any[]): Store;
getStore(key: string): Store;
removeStore(key: string): Store;
}
}
I am getting the following error:
src/app/App.ts(16,11): error TS2322: Type 'Actions' is not assignable to type 'MessageActions'.
Property 'newMessage' is missing in type 'Actions'.
src/app/App.ts(35,34): error TS2345: Argument of type 'typeof MessageStore' is not assignable to parameter of type 'Store'.
Property 'register' is missing in type 'typeof MessageStore'.'.
which is fair enough since I know I should probably use interface but then I won't be able to extend the classes in my code. Here's a link to the repo in case you want to try it
Would anyone be able to help me? I feel like I'm missing something obvious
As discussed on IRC, createStore(store: Store) means createStore takes an instance of type Store (or its subtypes), not a type that's a subtype of Store. For the latter, you want store to be of a type that contains a construct signature that returns Store or a subtype of Store. So
createActions(key: string, actions: Actions, constructorArgs?: any | any[]): Actions;
should be either
createActions(key: string, actions: { new(...args: any[]): Actions }, constructorArgs?: any | any[]): Actions;
or
createActions<T extends Actions>(key: string, actions: { new(...args: any[]): T }, constructorArgs?: any | any[]): T;
The latter allows you to return the same type you passed in instead of always returning Actions, should you need it.
The same needs to be done for createStore()
Also
this.register(messageActions.newMessage, this.handleNewMessage);
will cause problems because this
will be undefined in handleNewMessage. this.handleNewMessage returns a function, not a bound delegate like in other languages. You either want this.handleNewMessage.bind(this)
or message => this.handleNewMessage(message)
- the latter form requires you to explicitly write out all the parameters, whereas the former form doesn't but loses typechecking errors if the signatures of the parameter to register and of handleNewMessage ever disagree.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With