Home > database >  Why doesn't "in" narrow type for complex object?
Why doesn't "in" narrow type for complex object?

Time:10-22

I stumbled on issue in Typescript when I'm doing type narrowing using in for a complex object it doesn't properly narrow type unless I first extract it proxy variable.

type Animal = {
  fish: Fish;
  bird: Bird;
};
type Fish = {
  swim: () => void
};
type Bird = {
  fly: () => void
};

const globalA: Animal = {} as unknown as Animal;

function useDirectly(typew: keyof Animal) {
  if ("swim" in globalA[typew]) {
    return globalA[typew].swim();
  }

  return globalA[typew].fly();
}

function useProxyVariable(typew: keyof Animal) {
  const temp = globalA[typew];
  if ("swim" in temp) {
    return temp.swim();
  }

  return temp.fly();
}

Example on TS Playground

Does anyone know why is this happening and if there is a way to do type narrowing without using those proxy objects?

CodePudding user response:

Does anyone know why is this happening and if there is a way to do type narrowing without using those proxy objects?

It's just a limitation of the TypeScript compiler, it narrows the type of variables, not expressions. globalA[typew] is an expression. To narrow expressions like that, it would have to keep track of not just globalA but also typew. While it's easy for us to see that both of them are unchanged between the guard and the usage, this is just one of several pragmatic limitations of the compiler.

Using a temporary variable/constant as you've shown is how you get around it (and saves having to retype the expression).


Side note: I wouldn't use the term "proxy variable" (because of proxies); it's just a variable (well, a constant in your temp case

  • Related