Cody Haines
Cody Haines

Reputation: 1235

type guard on member of class

I feel like there may be some documentation I'm missing here, but basically what I'm trying to do is something like the following:

class Agent {
  public world: World | undefined;
  //...
  checkWorld(): this.world is World {
    return this.world !== undefined;
  }
}

Such that in a different function I could do something along the lines of the following:

const agent = new Agent();
if(!agent.checkWorld()) {
  throw new Error("No world assigned to agent");
} 
// Handle the agent as appropriate, knowing the world exists

However, typescript is certainly not happy with the checkWorld(): this.world is World syntax, saying 'All declarations of 'world' must have identical modifiers. My current solution is simply

if(agent.world === undefined) {
  throw new Error("No world assigned to agent");
}
agent.world = agent.world as World;
// Handle the agent as appropriate, knowing the world exists

However, this seems less than ideal. It's certainly possible this is something that I can't implicitly handle in typescript.

Of course, something like the following works:

checkWorld(w: World | undefined): w is World {
  return w !== undefined;
}
//...
if(!checkWorld(agent.world)) {
  throw new Error('No world assigned to agent');
}

But typescript isn't automatically acknowledging that agent.world isn't undefined past that point, so something like agent.world = agent.world as World is still necessary.

EDIT: I know this example is somewhat contrived, because the union type is only World or undefined, but in the actual code I have a host of different world types, and would like to do a type check if it's a specific type of world.

Upvotes: 1

Views: 252

Answers (1)

Nicholas Tower
Nicholas Tower

Reputation: 84982

Here's one option. Rather than trying to narrow the type on this.world, narrow it on this:

class Agent {
  public world: World | undefined;
  //...
  checkWorld(): this is { world: World } {
    return this.world !== undefined;
  }
}

const agent = new Agent();
if(!agent.checkWorld()) {
  throw new Error("No world assigned to agent");
} 
// At this point, agent's type is Agent & { world: World }
// You can write code knowing agent.world exists.

Playground link

Upvotes: 4

Related Questions