Skip to content

fix: types#801

Merged
delucis merged 4 commits into
boardgameio:masterfrom
Pong420:pong420/fix-types
Sep 13, 2020
Merged

fix: types#801
delucis merged 4 commits into
boardgameio:masterfrom
Pong420:pong420/fix-types

Conversation

@Pong420
Copy link
Copy Markdown
Contributor

@Pong420 Pong420 commented Sep 11, 2020

Checklist

  • Use a separate branch in your local repo (not master).
  • Test coverage is 100% (or you have a story for why it's ok).

Other then that, these helper types may be helpful?
typescript playground

helper-types

delucis
delucis previously approved these changes Sep 11, 2020
Copy link
Copy Markdown
Member

@delucis delucis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Do you want to have a go at integrating those helper types too? It’s a little tricky because you need to look-up moves in several places:

{
  // top-level moves
  moves: { /* ... */ },

  turn: {
    stages: {
      [stage]: {
        // stage-specific moves in top-level turn config
        moves: { /* ... */ },
      },
      // ...
    },
  },

  phases: {
    [phase]: {
      // phase-specific moves 
      moves: { /* ... */ },

      turn: {
        stages: {
          [stage]: {
            // stage-specific moves for this phase
            moves: { /* ... */ },
          },
          // ...
        },
      },
    },
    // ...
  },
};

(The client creates the move dispatcher for all of these even when they’re not active, so it’s safe to statically type this.)

@Pong420
Copy link
Copy Markdown
Contributor Author

Pong420 commented Sep 12, 2020

Cannot integrate those types into Game. I expect to export those types and let users handle them-self.

interface TicTacToeState {
   cells: (number | null)[]
}

const clickCell = (G; TicTacToeState. ctx: Ctx, id: number) => {}
cosnt moves = { clickCell };

type TicTacToesMoves = {
  [K in keyof typeof moves]: OmitArg<MoveMethod<typeof moves[K]>>;
};

export type TicTacToeBoardProps = BoardProps<TicTacToeState> & {
  moves: TicTacToesMoves ;
}

export function TicTacToeBoard(props: TicTacToeBoardProps) {
  // ....
}

Copy link
Copy Markdown
Member

@delucis delucis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is actually possible to fully type a client’s moves map, combining your approach with some utility types from ts-toolbelt, but I’d need to think a little more about how best to integrate this into the clients themselves. Merging this in the meantime — thanks for the fixes!

import { O, U } from 'ts-toolbelt';
import {
  Ctx,
  Game,
  LongFormMove,
  Move,
  MoveFn,
  MoveMap,
  PhaseConfig,
  PhaseMap,
  StageMap,
} from '../types';

/**
 * Convert a move function to its dispatcher, stripping the G & ctx arguments.
 * Dispatchers always return void.
 */
type OmitArgs<F> = F extends (G: any, ctx: Ctx, ...args: infer A) => any
  ? (...args: A) => void
  : never;

/**
 * Extract a move function from both short- and long-form move declarations.
 */
type MoveMethod<T extends Move> = T extends MoveFn
  ? T
  : T extends LongFormMove
  ? T['move']
  : never;

/**
 * Extract a move dispatcher from its short- or long-form move declaration.
 */
type MoveDispatcher<T extends Move> = OmitArgs<MoveMethod<T>>;

/**
 * Convert a map of move declarations to a map of move dispatchers.
 */
type MovesToDispatchers<T extends MoveMap> = {
  [K in keyof T]: MoveDispatcher<T[K]>;
};

/**
 * Extract a map of move dispatchers from a map of stage declarations.
 */
type StageDispatchers<T extends StageMap> = U.IntersectOf<
  O.UnionOf<
    {
      [K in keyof T]: MovesToDispatchers<T[K]['moves']>;
    }
  >
>;

/**
 * Extract a map of move dispatchers for a game’s top-level or a single phase.
 */
type DispatchersFromConfig<T extends PhaseConfig> = MovesToDispatchers<
  T['moves']
> &
  StageDispatchers<T['turn']['stages']>;

/**
 * Extract a map of move dispatchers from a map of phase declarations.
 */
type PhaseDispatchers<T extends PhaseMap> = U.IntersectOf<
  O.UnionOf<
    {
      [K in keyof T]: DispatchersFromConfig<T[K]>;
    }
  >
>;

/**
 * Extract a map of move dispatchers from a game declaration.
 */
type DispatchersFromGame<T extends Game> = {} & DispatchersFromConfig<T> &
  PhaseDispatchers<T['phases']>;

/**
 * Example in use:
 */
const game = {
  moves: {
    foo: (G: any, ctx: Ctx, arg: number) => {},
  },
  turn: {
    stages: {
      A: {
        moves: {
          bar: () => {},
        },
      },
    },
  },
};

type ClientMoves = DispatchersFromGame<typeof game>;
// ClientMoves['foo'] = (arg: number) => void
// ClientMoves['bar'] = () => void

@delucis delucis merged commit 0062e55 into boardgameio:master Sep 13, 2020
@Pong420 Pong420 deleted the pong420/fix-types branch September 13, 2020 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants