3

I have a very simple code:

const foo = (state: RootState): MyData => undefined;

This gives an error:

Type 'undefined' is not assignable to type 'MyData'.

Which is quite reasonable since my type MyData does not allow undefined.

But if I now write this:

const foo = (state: RootState): MyData => state.data?.myData;

Then it compiles without troubles. I don't understand what is going on here since if state.data is undefined then it should be really returning undefined and should be quite obvious to the compiler.

Am I missing something here?

P.S. This is the minimal example for types:

type State = {
  data: {
    myData: MyData;
  };
}

type MyData = {

}
4
  • 1
    Please show us (minimal versions of) the definitions of RootState and MyData. If I make reasonable guesses, TypeScript complains about both functions. Commented May 22, 2020 at 14:04
  • Did not think it is important, let me add it Commented May 22, 2020 at 14:05
  • 1
    When i make a reasonable guess at the types, typescript complains as you're asking it to (typescriptlang.org/play/…). Perhaps your type definitions have data and myData as never being undefined, so typescript deduces that the optional chaining is never going to matter? Commented May 22, 2020 at 14:06
  • 1
    It seems you are right! Did not think about it, typescript outsmarted me :) Commented May 22, 2020 at 14:08

1 Answer 1

3

It sounds like data is not optional in RootState.

TypeScript complains about both of these functions, since — as you say — MyData | undefined is not assignable to MyData:

interface RootState {
    data?: {
        myData: MyData;
    }
}

interface MyData {
    bar: string;
}

const foo1 = (state: RootState): MyData => undefined;

const foo2 = (state: RootState): MyData => state.data?.myData;

Playground link

But it's happy if data in RootState is not optional:

interface RootState {
    data: {
        myData: MyData;
    }
}

Playground link

It's happy because the TypeScript compiler knows that the ? there is non-functional, because data isn't optional, can't have the value undefined, and can't have the value null. So state.data.myData and state.data?.myData do exactly the same thing: yield a value of type MyData.

3
  • 1
    Thanks, that seems very correct, though I wish typescript did a warning that using optional chaining is not allowed, or rather an error like in C# e.g. Commented May 22, 2020 at 14:10
  • 2
    @IlyaChernomordik if you're using typescript-eslint, they have a rule which will alert you if you use optional chaining when it isn't necessary: github.com/typescript-eslint/typescript-eslint/blob/master/… Commented May 22, 2020 at 14:11
  • I do, thanks, will turn it on, it's default value is false Commented May 22, 2020 at 14:14

Not the answer you're looking for? Browse other questions tagged or ask your own question.