Repository: TypeScript
Issue: Null checks should allow narrowing of union types under strict null checks
Labels: Suggestion,Awaiting More Feedback

# Suggestion

<!--
  Please fill in each section completely. Thank you!
-->

## 🔍 Search Terms

<!--
  💡 Did you know? TypeScript has over 2,000 open suggestions!
  🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress.
  The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests

  Replace the text below:
-->

type narrowing, union, null, strict null checks

## ✅ Viability Checklist

<!--
   Suggestions that don't meet all these criteria are very, very unlikely to be accepted.
   We always recommend reviewing the TypeScript design goals before investing time writing
   a proposal for ideas outside the scope of the project.
-->
My suggestion meets these guidelines:

* [ * ] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [ * ] This wouldn't change the runtime behavior of existing JavaScript code
* [ * ] This could be implemented without emitting different JS based on the types of the expressions
* [ * ] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [ * ] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Suggestion

<!-- A summary of what you'd like to see added or changed -->
A null-check should be able to narrow down a union if strict null checks are enabled. If a property is nullable in only one element of the union, then `if (o.property == null)` should narrow the type to that element of the union.

```typescript
type OptionA = {
    foo: string;
}
type OptionB = {
    foo: string | null;
    baz: string;
}
type Union = OptionA | OptionB;


function f(value: Union): string {
    if (value.foo == null) {
        return value.baz; // should compile, but doesn't: Property 'baz' does not exist on type 'Union'.
    } else {
        return 'Was OptionA';
    }
}
```

## 💻 Use Cases

<!--
  What do you want to use this for?
  What shortcomings exist with current approaches?
  What workarounds are you using in the meantime?
-->
A calculation can be done in one of two ways, either using inputs A and B or using input C. User might still specify A, B and C, but one of the two way must be given. This can be expressed as follows:
```typescript
type OptionA =  {
  a: number;
  b: number;
  c: number | null;
}
type OptionB = {
  a: number | null;
  b: number | null;
  c: number;
}

function calc(input: OptionA | OptionB): number {
  if (input.a != null && input.b != null) {
    return input.a * input.b;
  } else {
    return input.c * 10; // compiler issues an error that input.c can be null, which is not correct
  }
}
```

As a workaround I am using a manual type guard:
```typescript
function isOptionA(input: OptionA | OptionB): input is OptionA {
  return input.a != null && input.b != null;
}
```