Home > OS >  How to handle typing a response that could be success or error?
How to handle typing a response that could be success or error?

Time:01-06

I have code like so:

socket.emit(ClientActions.LOAD_GAME_STATE, (response: GameState | ErrorResponse) => {
       // use response
});

The trouble is that if I try to access properties I would expect on a GameState object, it predictably gives me an error because those properties don't exist on the ErrorResponse type.

How can I express that the response could be data or an error, and type it and use it accordingly? Is there a recommended way?

CodePudding user response:

That is the recommended way to type it, and to narrow down the type to either success or error, you should use an if statement as a type guard:

socket.emit(ClientActions.LOAD_GAME_STATE, (response: GameState | ErrorResponse) => {
    if ('<a property only in ErrorResponse>' in response) {
       // response is of type `ErrorResponse`
    } else {
       // response is of type `GameState`
    }
});

CodePudding user response:

For more cohesive and expansible typings I would suggest something like the following (specifics depend on your implementation)

type ResponseTypes = "success" | "error"; // You may want to get more specific/granular here

interface SocketResponse {
  type: ResponseTypes;
  // Other info on every socket response
}

interface SocketError extends SocketResponse {
  type: "error";
  errorMessage: string;
}

interface SocketGameState extends SocketResponse {
  type: "success";
  gameState: GameState;
}

Your original code would become

socket.emit(ClientActions.LOAD_GAME_STATE, (response: SocketGameState | SocketError) => {
  if (response.type === "error") {
    ... // Narrows to SocketError
  } else {
    ... // Narrows to SocketGameState
  }
});

I think this solution would allow you the most flexibility to add many new kinds of response types while handling errors in a consistent, intuitively-typed way.

  • Related