Skip to content

Commit f23c180

Browse files
Merge pull request #25287 from Microsoft/skipToNonNullTargets
Skip to non null targets in error messages
2 parents 2a19580 + 584e923 commit f23c180

7 files changed

+119
-11
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10631,6 +10631,23 @@ namespace ts {
1063110631
target = getSimplifiedType(target);
1063210632
}
1063310633

10634+
// Try to see if we're relating something like `Foo` -> `Bar | null | undefined`.
10635+
// If so, reporting the `null` and `undefined` in the type is hardly useful.
10636+
// First, see if we're even relating an object type to a union.
10637+
// Then see if the target is stripped down to a single non-union type.
10638+
// Note
10639+
// * We actually want to remove null and undefined naively here (rather than using getNonNullableType),
10640+
// since we don't want to end up with a worse error like "`Foo` is not assignable to `NonNullable<T>`"
10641+
// when dealing with generics.
10642+
// * We also don't deal with primitive source types, since we already halt elaboration below.
10643+
if (target.flags & TypeFlags.Union && source.flags & TypeFlags.Object &&
10644+
(target as UnionType).types.length <= 3 && maybeTypeOfKind(target, TypeFlags.Nullable)) {
10645+
const nullStrippedTarget = extractTypesOfKind(target, ~TypeFlags.Nullable);
10646+
if (!(nullStrippedTarget.flags & (TypeFlags.Union | TypeFlags.Never))) {
10647+
target = nullStrippedTarget;
10648+
}
10649+
}
10650+
1063410651
// both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases
1063510652
if (source === target) return Ternary.True;
1063610653

@@ -12223,7 +12240,7 @@ namespace ts {
1222312240
if (deferredGlobalNonNullableTypeAlias !== unknownSymbol) {
1222412241
return getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]);
1222512242
}
12226-
return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); // Type alias unavailable, fall back to non-higherorder behavior
12243+
return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); // Type alias unavailable, fall back to non-higher-order behavior
1222712244
}
1222812245

1222912246
function getNonNullableType(type: Type): Type {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
tests/cases/compiler/elaboratedErrorsOnNullableTargets01.ts(4,1): error TS2322: Type '{ foo: { bar: number; }; }' is not assignable to type '{ foo: { bar: string; }; }'.
2+
Types of property 'foo' are incompatible.
3+
Type '{ bar: number; }' is not assignable to type '{ bar: string; }'.
4+
Types of property 'bar' are incompatible.
5+
Type 'number' is not assignable to type 'string'.
6+
tests/cases/compiler/elaboratedErrorsOnNullableTargets01.ts(6,1): error TS2322: Type '{ foo: { bar: string; }; }' is not assignable to type '{ foo: { bar: number; }; }'.
7+
Types of property 'foo' are incompatible.
8+
Type '{ bar: string; }' is not assignable to type '{ bar: number; }'.
9+
Types of property 'bar' are incompatible.
10+
Type 'string' is not assignable to type 'number'.
11+
12+
13+
==== tests/cases/compiler/elaboratedErrorsOnNullableTargets01.ts (2 errors) ====
14+
export declare let x: null | { foo: { bar: string | null } | undefined } | undefined;
15+
export declare let y: { foo: { bar: number | undefined } };
16+
17+
x = y;
18+
~
19+
!!! error TS2322: Type '{ foo: { bar: number; }; }' is not assignable to type '{ foo: { bar: string; }; }'.
20+
!!! error TS2322: Types of property 'foo' are incompatible.
21+
!!! error TS2322: Type '{ bar: number; }' is not assignable to type '{ bar: string; }'.
22+
!!! error TS2322: Types of property 'bar' are incompatible.
23+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
24+
25+
y = x;
26+
~
27+
!!! error TS2322: Type '{ foo: { bar: string; }; }' is not assignable to type '{ foo: { bar: number; }; }'.
28+
!!! error TS2322: Types of property 'foo' are incompatible.
29+
!!! error TS2322: Type '{ bar: string; }' is not assignable to type '{ bar: number; }'.
30+
!!! error TS2322: Types of property 'bar' are incompatible.
31+
!!! error TS2322: Type 'string' is not assignable to type 'number'.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [elaboratedErrorsOnNullableTargets01.ts]
2+
export declare let x: null | { foo: { bar: string | null } | undefined } | undefined;
3+
export declare let y: { foo: { bar: number | undefined } };
4+
5+
x = y;
6+
7+
y = x;
8+
9+
//// [elaboratedErrorsOnNullableTargets01.js]
10+
"use strict";
11+
exports.__esModule = true;
12+
exports.x = exports.y;
13+
exports.y = exports.x;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/compiler/elaboratedErrorsOnNullableTargets01.ts ===
2+
export declare let x: null | { foo: { bar: string | null } | undefined } | undefined;
3+
>x : Symbol(x, Decl(elaboratedErrorsOnNullableTargets01.ts, 0, 18))
4+
>foo : Symbol(foo, Decl(elaboratedErrorsOnNullableTargets01.ts, 0, 30))
5+
>bar : Symbol(bar, Decl(elaboratedErrorsOnNullableTargets01.ts, 0, 37))
6+
7+
export declare let y: { foo: { bar: number | undefined } };
8+
>y : Symbol(y, Decl(elaboratedErrorsOnNullableTargets01.ts, 1, 18))
9+
>foo : Symbol(foo, Decl(elaboratedErrorsOnNullableTargets01.ts, 1, 23))
10+
>bar : Symbol(bar, Decl(elaboratedErrorsOnNullableTargets01.ts, 1, 30))
11+
12+
x = y;
13+
>x : Symbol(x, Decl(elaboratedErrorsOnNullableTargets01.ts, 0, 18))
14+
>y : Symbol(y, Decl(elaboratedErrorsOnNullableTargets01.ts, 1, 18))
15+
16+
y = x;
17+
>y : Symbol(y, Decl(elaboratedErrorsOnNullableTargets01.ts, 1, 18))
18+
>x : Symbol(x, Decl(elaboratedErrorsOnNullableTargets01.ts, 0, 18))
19+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/compiler/elaboratedErrorsOnNullableTargets01.ts ===
2+
export declare let x: null | { foo: { bar: string | null } | undefined } | undefined;
3+
>x : { foo: { bar: string; }; }
4+
>null : null
5+
>foo : { bar: string; }
6+
>bar : string
7+
>null : null
8+
9+
export declare let y: { foo: { bar: number | undefined } };
10+
>y : { foo: { bar: number; }; }
11+
>foo : { bar: number; }
12+
>bar : number
13+
14+
x = y;
15+
>x = y : { foo: { bar: number; }; }
16+
>x : { foo: { bar: string; }; }
17+
>y : { foo: { bar: number; }; }
18+
19+
y = x;
20+
>y = x : { foo: { bar: string; }; }
21+
>y : { foo: { bar: number; }; }
22+
>x : { foo: { bar: string; }; }
23+

tests/baselines/reference/nestedFreshLiteral.errors.txt

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
tests/cases/compiler/nestedFreshLiteral.ts(12,21): error TS2322: Type '{ nested: { prop: { colour: string; }; }; }' is not assignable to type 'NestedCSSProps'.
22
Types of property 'nested' are incompatible.
3-
Type '{ prop: { colour: string; }; }' is not assignable to type 'NestedSelector | undefined'.
4-
Type '{ prop: { colour: string; }; }' is not assignable to type 'NestedSelector'.
5-
Types of property 'prop' are incompatible.
6-
Type '{ colour: string; }' is not assignable to type 'CSSProps'.
7-
Object literal may only specify known properties, but 'colour' does not exist in type 'CSSProps'. Did you mean to write 'color'?
3+
Type '{ prop: { colour: string; }; }' is not assignable to type 'NestedSelector'.
4+
Types of property 'prop' are incompatible.
5+
Type '{ colour: string; }' is not assignable to type 'CSSProps'.
6+
Object literal may only specify known properties, but 'colour' does not exist in type 'CSSProps'. Did you mean to write 'color'?
87

98

109
==== tests/cases/compiler/nestedFreshLiteral.ts (1 errors) ====
@@ -23,9 +22,8 @@ tests/cases/compiler/nestedFreshLiteral.ts(12,21): error TS2322: Type '{ nested:
2322
~~~~~~~~~~~~~
2423
!!! error TS2322: Type '{ nested: { prop: { colour: string; }; }; }' is not assignable to type 'NestedCSSProps'.
2524
!!! error TS2322: Types of property 'nested' are incompatible.
26-
!!! error TS2322: Type '{ prop: { colour: string; }; }' is not assignable to type 'NestedSelector | undefined'.
27-
!!! error TS2322: Type '{ prop: { colour: string; }; }' is not assignable to type 'NestedSelector'.
28-
!!! error TS2322: Types of property 'prop' are incompatible.
29-
!!! error TS2322: Type '{ colour: string; }' is not assignable to type 'CSSProps'.
30-
!!! error TS2322: Object literal may only specify known properties, but 'colour' does not exist in type 'CSSProps'. Did you mean to write 'color'?
25+
!!! error TS2322: Type '{ prop: { colour: string; }; }' is not assignable to type 'NestedSelector'.
26+
!!! error TS2322: Types of property 'prop' are incompatible.
27+
!!! error TS2322: Type '{ colour: string; }' is not assignable to type 'CSSProps'.
28+
!!! error TS2322: Object literal may only specify known properties, but 'colour' does not exist in type 'CSSProps'. Did you mean to write 'color'?
3129
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
export declare let x: null | { foo: { bar: string | null } | undefined } | undefined;
3+
export declare let y: { foo: { bar: number | undefined } };
4+
5+
x = y;
6+
7+
y = x;

0 commit comments

Comments
 (0)