typescripttypescript-utility

How do I remove both an undefined union and optionality from an attribute?


Here is a reduced code snippet to illustrate the issue:

type A = {
  b?: number | undefined;
}

const a: NonNullable<Required<A>> = {
  b: 0,
};

a.b++;

Currently, the a.b++ operation produces this TSC error:

TS18048: 'a.b' is possibly 'undefined'.

More descriptive error:

return new TSError(diagnosticText, diagnosticCodes, diagnostics);
           ^
TSError: ⨯ Unable to compile TypeScript:
project/src/test.ts:9:1 - error TS2532: Object is possibly 'undefined'.

9 a.b++;
  ~~~

It seems to only happen with the exactOptionalPropertyTypes option enabled.

Playground link

My assumption was that the combination of Required and NonNullable should yield a type in which b should always be defined, but it doesn't seem to be the case.

Is it possible to achieve this?


Solution

  • The NonNullable in your code doesn't do what you're expecting: It would remove null and undefined from A itself if it were a union containing them, but it doesn't do anything to A's properties.

    But you can create a mapped type to do it:

    type NoNullableProperties<T> = {
        [Key in keyof T]: NonNullable<T[Key]>;
    };
    

    Then this works:

    const a: NoNullableProperties<Required<A>> = {
        b: 0,
    };
    
    a.b++;
    console.log(a.b);
    

    Playground link