Моделирование данных Typescript, используемое как передним, так и внутренним интерфейсом - классы или интерфейсы? - PullRequest
0 голосов
/ 10 апреля 2020

Интересно, как лучше распределить одни и те же типы данных между клиентом (React) и сервером (Express + Socket.IO).

В моей игре у меня разные комнаты, каждая комната сохраняет текущее состояние, например:

class GameRoom {
    players: Player[];
    started: boolean;
    currentPlayerTurn; Player;
    dices: [number, number];

    constructor({players = [], started = false, currentPlayerTurn = null, dices = [1,1]) {
        this.players = players;
        this.started = started;
        this.currentPlayerTurn = currentPlayerTurn;
        this.dices = dices;
    }

    startGame() {
        this.currentPlayerTurn = this.players[0];
        this.started = true;
    }

    // etc..
}

Комната генерируется на сервере, отправляется клиенту как JSON, а затем перестраивается на клиенте. Я синхронизирую c данных с событиями сокетов, и все идеально.

Но есть проблема со стороной React: изменение GameRoom свойств не вызовет повторного рендеринга. Это означает, что я должен forceRerender() каждый раз, когда что-то редактировать, или слушать изменения класса. Оба варианта - беспорядок, и я подробно описал его в этом вопросе .

Этот беспорядок заставил меня думать, что, возможно, занятия - не лучший способ для go. Использование интерфейса полностью решит эту проблему, но я теряю функции экземпляра, такие как GameRoom.startGame(), которые должны быть превращены в служебные функции, такие как:

export function startGame(gameRoom: GameRoom) {
    gameRoom.currentPlayerTurn = gameRoom.players[0];
    gameRoom.started = true;
}

, что является еще одним беспорядком, поскольку они скрыты в коде, и разработчик должен знать, что они существуют , а не редактировать gameRoom напрямую.

Если вы, ребята, имеете представление о том, как моделировать мои типы данных, я бы более чем рад слышать.

Спасибо!

1 Ответ

0 голосов
/ 10 апреля 2020

Я бы go с функциональным подходом. Я не большой поклонник классов в JS.

Определите тип для вашей игры, но установите свойства только для чтения. Это скажет разработчику, что он не должен изменять GameRoom.

export type GameRoom = {
    readonly players: Player[];
    readonly started: boolean;
    readonly currentPlayerTurn: Player;
    readonly dices: [number, number];
}

Затем вы можете определить все ваши изменения как чистые функции, чтобы вы определяли свои входные данные и создавали новый объект, который является вашим обновленным GameRoom. , Это упрощает тестирование и отслеживание изменений.

export function startGame(gameRoom: GameRoom): GameRoom {
    return {
        ...gameRoom,
        currentPlayerTurn: gameRoom.players[0],
        started: true
    }
}

Кроме того, вы можете использовать что-то вроде Redux и определять свои изменения как набор действий. (например, add-player, start-game и т. д. c). Затем вы можете отправлять эти действия из любого места вашего кода.

Самое замечательное в использовании неизменяемости - это каждый раз, когда вы вносите изменения в свой объект. , вы возвращаете новый, поэтому React всегда будет перерисовывать соответствующим образом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...