Search code examples
typescriptlogical-operatorsunion-types

Why does typescript resolve a union type to possible empty string when using logic operators?


I am trying to guard against a null object using logic operators. The object which might be null contains a string and a union type as attributes. If I use "&&" operator to check if the object is not null, the whole expression is evaluated to another union type, which allows empty strings, and I have a type mismatch error.

I've verified that if instead of using the logic operator, I use an IF statement, the code works fine, but I want to understand why is it not being resolved as I expected.

type FooType = 'aaa' | 'bbb' | 'ccc';
​
interface IFoo {
  type: FooType;
  id: string;
}
​
type FooAlias = IFoo;
​
const fooObject = {type: 'aaa', id: '111'} as IFoo;
​
const fooObject2: FooAlias = {
  id: fooObject && fooObject.id,
  type: fooObject && fooObject.type
  /* The line above complains:
  Type '"" | "aaa" | "bbb" | "ccc"' is not assignable to type 'FooType'.
  Type '""' is not assignable to type 'FooType'.ts(2322)*/
};

if instead of type: fooObject && fooObject.type I use type: fooObject? fooObject.type : null it works, because it seems like it correctly dos not assume it might be an empty string.


Solution

  • This is a reported bug. If strictNullChecks are off an extra "" sneaks in.

    Until this gets fixed you can use a type assertion or a ternary operator:

    const fooObject2: FooAlias = {
      id: fooObject && fooObject.id,
      //type: (fooObject && fooObject.type) as FooType
      type: fooObject ? fooObject.type : undefined
    };
    

    Play