boardgameio / boardgame.io

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

Plugin setup ctx issue when using typescript. #1050

Open walkerkd opened 2 years ago

walkerkd commented 2 years ago

I am attempting to use a plugin for the 1st time (having seen a recent reference to the bgio-effects plugin) ... it looks just like something I really want to use.

All was going fine until I got to the point of adding my game to the game server, and then the typescript compiler is throwing an error.

I have reduce this down to a small example:

import { EffectsCtxMixin } from 'bgio-effects';
import { EffectsPlugin } from 'bgio-effects/plugin';
import { Ctx, Game } from 'boardgame.io';
import { Server } from 'boardgame.io/server';

const EffectsConfig = {
    effects: {
        mediocreCards: {},
    },
} as const;

interface GameState {
    dummy: number;
}

export const MediocrityGame: Game<
    GameState,
    Ctx & EffectsCtxMixin<typeof EffectsConfig>
> = {
    name: 'Mediocrity',

    plugins: [EffectsPlugin(EffectsConfig)],
};

export const server = Server({
    games: [MediocrityGame],
});

This causes the following error to be generated on the games: [MediocrityGame], line:

Type 'Game<GameState, Ctx & EffectsCtxMixin<{ readonly effects: { readonly mediocreCards: {}; }; }>, any>' is not assignable to type 'Game<any, Ctx, any>'.
  Types of property 'setup' are incompatible.
    Type '((ctx: Ctx & EffectsCtxMixin<{ readonly effects: { readonly mediocreCards: {}; }; }>, setupData?: any) => GameState) | undefined' is not assignable to type '((ctx: Ctx, setupData?: any) => any) | undefined'.
      Type '(ctx: Ctx & EffectsCtxMixin<{ readonly effects: { readonly mediocreCards: {}; }; }>, setupData?: any) => GameState' is not assignable to type '(ctx: Ctx, setupData?: any) => any'.
        Types of parameters 'ctx' and 'ctx' are incompatible.

Am I doing something wrong?

As I was looking at how plugins worked, I was wondering if the supplied PlayerPlugin should also provide a PlayerCtxMixin to allow it to be added to the default Ctx (otherwise I cannot see how to use the PlayerPlugin when using typescript?

delucis commented 2 years ago

Thanks for this report. I think your usage is correct, but the typings for the Server function need to be updated to handle customised ctx types.

A quick workaround may be to use a type assertion when passing the game to the server:

export const server = Server({
    games: [MediocrityGame as Game],
});

There aren’t really any drawbacks to asserting there I don’t think, but it would still be good to fix the server typing to handle this automatically.

The PlayerPlugin does export a type to use like the mixin for bgio-effects, albeit one that is named very confusingly:

import { Ctx, Game } from 'boardgame.io';
import { PlayerPlugin, PluginPlayer } from 'boardgame.io/plugins';

interface PlayerState {
  score: number;
}

const game: Game<G, Ctx & PlayerPlugin<PlayerState>> = {
  plugins: [
    PluginPlayer<PlayerState>({ /* ... */ })
  ],
};
walkerkd commented 2 years ago

Thanks for the workaround.

I actually had to do:

 export const server = Server({
     games: [MediocrityGame as unknown as Game],
});

because the compiler thinks I might be doing something wrong .

Also thanks for pointing out that the PlayerPlugin does have a equivalent to the Effects Mixin.

I guess a document update with a typescript example for the PlayerPlugin might help others not make the same mistake..

Anyway, great stuff ... now I'm off to work on using the plugins.