0

I have the following code:

interface A {
    a: number;
}

interface B extends A {
    b: number;
}

const instanceOfB: B = {
    a: 1,
    b: 2,
}

const myFunct = (arg: A | B) => {
    const myNumber = arg.b ?? 42;
    console.log(myNumber);
};

myFunct(instanceOfB);

Inside myFunct I want to access the b property of arg, which might or might not exist on arg depending on whether or not arg is of type B. In case it does not exist and the access returns undefined, I use the fallback value of 42.
Typescript complains that Property 'b' does not exist on type 'A | B'., which is true. A | B is basically the same as A since only a is shared between them both, yet I would still like to try to access it and use my fallback value if it doesn't. I know I could change my JavaScript to satisfy Typescript by changing the relevant line to e.g. const myNumber = "b" in arg ? arg.b : 42;, but I really don't want to change my JavaScript code just to make Typescript happy when my code is (in my opinion) perfectly fine.

Is there a Typescript only solution to my Typescript only problem?

Also, if someone knows, I would be very interested in why Typescript complains about arg.b ?? 42 but not "b" in arg ? arg.b : 42.

Teiem
  • 1,329
  • 15
  • 32
  • Just use `in` operator in this case. See [example](https://tsplay.dev/mq5Kqm). `in` operator works well with unions or try [StrictUnion](https://tsplay.dev/w2ad1W) helper. See [this](https://stackoverflow.com/questions/65805600/type-union-not-checking-for-excess-properties#answer-65805753) answer – captain-yossarian from Ukraine Jun 02 '22 at 09:02

1 Answers1

0

The ?? operator goes to the "otherwise" case for both null and undefined values. In other words, it's not the same as checking for the existence of a key.

"b" in arg works because in will return true for a key that has been set to null or undefined:

const arg = { a: undefined }
console.log(arg.a ?? "not in") // not in
console.log("a" in arg ? "in" : "not in") // in

arg.a ?? accesses the value of a, but arg may not have an a property, so TypeScript tells you that. "a" in arg doesn't access arg.a, it checks to see if it exists.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
MHebes
  • 2,290
  • 1
  • 16
  • 29