-
Notifications
You must be signed in to change notification settings - Fork 13k
Closed
Labels
DuplicateAn existing issue was already createdAn existing issue was already created
Description
TypeScript Version: typescript@3.7.0-dev.20190917 (typescript@next)
Search Terms: union property type narrowing
Note: this is two bugs in one but they look related. "Issue 2" might actually be more damning.
Issue 1
Code
// Compile with `tsc --strictNullChecks` maybe1.ts
type Base = { bar: number };
type MaybeFoo = Base & { foo: string | null };
type HasFoo = MaybeFoo & { foo: string };
export function useMaybeFoo(maybeFoo: MaybeFoo) {
if (maybeFoo.foo !== null) {
const hasFoo: HasFoo = maybeFoo;
}
}
Expected behavior:
Should compile because the conditional should have narrowed the MaybeFoo to a HasFoo.
Actual behavior:
maybe1.ts:7:11 - error TS2322: Type 'MaybeFoo' is not assignable to type 'HasFoo'.
Type 'MaybeFoo' is not assignable to type '{ foo: string; }'.
Types of property 'foo' are incompatible.
Type 'string | null' is not assignable to type 'string'.
Type 'null' is not assignable to type 'string'.
7 const hasFoo: HasFoo = maybeFoo;
~~~~~~
Playground Link: click
Related Issues: had a quick search but couldn't anything
Workaround
This code is exactly the same, but compiles
// Compile with `tsc --strictNullChecks` maybe2.ts
type Base = { bar: number };
type NoFoo = Base & { foo: null };
type HasFoo = Base & { foo: string };
type MaybeFoo = NoFoo | HasFoo;
export function useMaybeFoo(maybeFoo: MaybeFoo) {
if (maybeFoo.foo !== null) {
const hasFoo: HasFoo = maybeFoo;
}
}
Playground Link click
Issue 2
Now let's try using the same type definitions as maybe2.ts, but try creating a MaybeFoo:
// Compile with `tsc --strictNullChecks` maybe3.ts
type Base = { bar: number };
type NoFoo = Base & { foo: null };
type HasFoo = Base & { foo: string };
type MaybeFoo = NoFoo | HasFoo;
export function makeMaybeFoo(foo: string | null): void {
const maybeFoo: MaybeFoo = {foo: foo, bar: 3};
}
Expected behavior:
Should compile.
Actual behavior:
maybe3.ts:7:9 - error TS2322: Type '{ foo: string | null; bar: number; }' is not assignable to type 'MaybeFoo'.
Type '{ foo: string | null; bar: number; }' is not assignable to type 'HasFoo'.
Type '{ foo: string | null; bar: number; }' is not assignable to type '{ foo: string; }'.
Types of property 'foo' are incompatible.
Type 'string | null' is not assignable to type 'string'.
Type 'null' is not assignable to type 'string'.
7 const maybeFoo: MaybeFoo = {foo: foo, bar: 3};
Playground Link click
Issue 2 Workaround
Changing back to the original type definitions fixes it:
// Compile with `tsc --strictNullChecks` maybe4.ts
type Base = { bar: number };
type MaybeFoo = Base & { foo: string | null };
type HasFoo = MaybeFoo & { foo: string };
export function makeMaybeFoo(foo: string | null): void {
const maybeFoo: MaybeFoo = {foo: foo, bar: 3};
}
Playground Link: click
Metadata
Metadata
Assignees
Labels
DuplicateAn existing issue was already createdAn existing issue was already created