diff --git a/packages/compiler-cli/src/ngtsc/typecheck/extended/checks/nullish_coalescing_not_nullable/index.ts b/packages/compiler-cli/src/ngtsc/typecheck/extended/checks/nullish_coalescing_not_nullable/index.ts index eaa0914d15f2d..6b4473efaaa9d 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/extended/checks/nullish_coalescing_not_nullable/index.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/extended/checks/nullish_coalescing_not_nullable/index.ts @@ -35,6 +35,12 @@ class NullishCoalescingNotNullableCheck extends return []; } const typeLeft = symbolLeft.tsType; + if (typeLeft.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { + // We should not make assumptions about the any and unknown types; using a nullish coalescing + // operator is acceptable for those. + return []; + } + // If the left operand's type is different from its non-nullable self, then it must // contain a null or undefined so this nullish coalescing operator is useful. No diagnostic to // report. diff --git a/packages/compiler-cli/src/ngtsc/typecheck/extended/test/checks/nullish_coalescing_not_nullable/nullish_coalescing_not_nullable_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/extended/test/checks/nullish_coalescing_not_nullable/nullish_coalescing_not_nullable_spec.ts index e79a8f72cc77f..ae554cee9c0d0 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/extended/test/checks/nullish_coalescing_not_nullable/nullish_coalescing_not_nullable_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/extended/test/checks/nullish_coalescing_not_nullable/nullish_coalescing_not_nullable_spec.ts @@ -74,6 +74,42 @@ runInEachFileSystem(() => { expect(diags.length).toBe(0); }); + it('should not produce nullish coalescing warning for the any type', () => { + const fileName = absoluteFrom('/main.ts'); + const {program, templateTypeChecker} = setup([{ + fileName, + templates: { + 'TestCmp': `{{ var1 ?? 'foo' }}`, + }, + source: 'export class TestCmp { var1: any; }' + }]); + const sf = getSourceFileOrError(program, fileName); + const component = getClass(sf, 'TestCmp'); + const extendedTemplateChecker = new ExtendedTemplateCheckerImpl( + templateTypeChecker, program.getTypeChecker(), [nullishCoalescingNotNullableFactory], + {} /* options */); + const diags = extendedTemplateChecker.getDiagnosticsForComponent(component); + expect(diags.length).toBe(0); + }); + + it('should not produce nullish coalescing warning for the unknown type', () => { + const fileName = absoluteFrom('/main.ts'); + const {program, templateTypeChecker} = setup([{ + fileName, + templates: { + 'TestCmp': `{{ var1 ?? 'foo' }}`, + }, + source: 'export class TestCmp { var1: unknown; }' + }]); + const sf = getSourceFileOrError(program, fileName); + const component = getClass(sf, 'TestCmp'); + const extendedTemplateChecker = new ExtendedTemplateCheckerImpl( + templateTypeChecker, program.getTypeChecker(), [nullishCoalescingNotNullableFactory], + {} /* options */); + const diags = extendedTemplateChecker.getDiagnosticsForComponent(component); + expect(diags.length).toBe(0); + }); + it('should not produce nullish coalescing warning for a type that includes undefined', () => { const fileName = absoluteFrom('/main.ts'); const {program, templateTypeChecker} = setup([{ @@ -165,7 +201,7 @@ runInEachFileSystem(() => { }, source: ` export class TestCmp { - func: (): string | null => null; + func = (): string | null => null; } `, },