boardgameio / boardgame.io

State Management and Multiplayer Networking for Turn-Based Games
https://boardgame.io
MIT License
9.99k stars 704 forks source link

Typescript error when calling moves in tests #587

Closed janKir closed 4 years ago

janKir commented 4 years ago

I implemented my phases like this:

import { PhaseConfig, ... } from "boardgame.io";

export const phase: PhaseConfig = {
  moves: {
    moveA(G, ctx, more, args): "INVALID_MOVE" | undefined { ... }
  }
};

Which works fine -- expect when I wanted to test the moves and called them like this:

import { phase } from "./phase";
...
phase.moves!.moveA(G, ctx, more, args);
...

This ends in the following error: This expression is not callable. No constituent of type 'Move' is callable.ts(2349). Which is defined as:

export declare type Move = Function | LongFormMove;

I'm not really sure how this Function interface works but I haven't found any explanations on when and how to use it for typing functions. It's not mentioned in the typescript handbook. So I guess the use of this interface causes this error.

Probably Move should be defined as generic type taking a tuple for all custom params.

Workaround

To avoid this error I simply exported the move independently from the phase and imported it directly into my test:

export function moveA(G, ctx, more, args) { ... }

export const phase: PhaseConfig = {
  moves: {
    moveA
  }
};
import { moveA } from "./phase";
...
moveA(G, ctx, more, args);
...
delucis commented 4 years ago

Ah, this is a broader problem. Quite a few places in the interfaces that expect functions of one form or another are typed as Function, which is actually the function constructor not a generic function type (which could be something like (...args: any[]) => any). I’ll try to go through fixing those.

For now, to quickly get your test working, if you remove PhaseConfig as the explicit type of your phase object, you’d probably be OK, because I think Typescript would still error if you passed a malformed phase to boardgame.io and the type of moveA would be inferred correctly instead of using the Function type.