Skip to content

Commit 6fd8a20

Browse files
crisbetoalxhub
authored andcommitted
refactor(compiler-cli): move two-way binding fix behind flag (#59002)
Moves the fix for type checking the event side of two-way bindings behind a compiler flag so that we can roll it out in v20. PR Close #59002
1 parent c5c20e9 commit 6fd8a20

File tree

9 files changed

+26
-8
lines changed

9 files changed

+26
-8
lines changed

packages/compiler-cli/src/ngtsc/core/api/src/options.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ export interface InternalOptions {
120120
* @internal
121121
*/
122122
_enableHmr?: boolean;
123+
124+
// TODO(crisbeto): this is a temporary flag that will be removed in v20.
125+
/**
126+
* Whether to check the event side of two-way bindings.
127+
*/
128+
_checkTwoWayBoundEvents?: boolean;
123129
}
124130

125131
/**

packages/compiler-cli/src/ngtsc/core/src/compiler.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,7 @@ export class NgCompiler {
10271027
const strictTemplates = !!this.options.strictTemplates;
10281028

10291029
const useInlineTypeConstructors = this.programDriver.supportsInlineOperations;
1030+
const checkTwoWayBoundEvents = this.options['_checkTwoWayBoundEvents'] ?? false;
10301031

10311032
// Check whether the loaded version of `@angular/core` in the `ts.Program` supports unwrapping
10321033
// writable signals for type-checking. If this check fails to find a suitable .d.ts file, fall
@@ -1080,6 +1081,7 @@ export class NgCompiler {
10801081
unusedStandaloneImports:
10811082
this.options.extendedDiagnostics?.defaultCategory || DiagnosticCategoryLabel.Warning,
10821083
allowSignalsInTwoWayBindings,
1084+
checkTwoWayBoundEvents,
10831085
};
10841086
} else {
10851087
typeCheckingConfig = {
@@ -1114,6 +1116,7 @@ export class NgCompiler {
11141116
unusedStandaloneImports:
11151117
this.options.extendedDiagnostics?.defaultCategory || DiagnosticCategoryLabel.Warning,
11161118
allowSignalsInTwoWayBindings,
1119+
checkTwoWayBoundEvents,
11171120
};
11181121
}
11191122

packages/compiler-cli/src/ngtsc/typecheck/api/api.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,11 @@ export interface TypeCheckingConfig {
357357
* Whether to descend into the bodies of control flow blocks (`@if`, `@switch` and `@for`).
358358
*/
359359
checkControlFlowBodies: boolean;
360+
361+
/**
362+
* Whether the event side of a two-way binding should be type checked.
363+
*/
364+
checkTwoWayBoundEvents: boolean;
360365
}
361366

362367
export type TemplateSourceMapping =

packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3094,7 +3094,8 @@ function tcbCreateEventHandler(
30943094
const handler = tcbEventHandlerExpression(event.handler, tcb, scope);
30953095
const statements: ts.Statement[] = [];
30963096

3097-
if (event.type === ParsedEventType.TwoWay) {
3097+
// TODO(crisbeto): remove the `checkTwoWayBoundEvents` check in v20.
3098+
if (event.type === ParsedEventType.TwoWay && tcb.env.config.checkTwoWayBoundEvents) {
30983099
// If we're dealing with a two-way event, we create a variable initialized to the unwrapped
30993100
// signal value of the expression and then we assign `$event` to it. Note that in most cases
31003101
// this will already be covered by the corresponding input binding, however it allows us to

packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,7 @@ describe('type check blocks', () => {
981981
controlFlowPreventingContentProjection: 'warning',
982982
unusedStandaloneImports: 'warning',
983983
allowSignalsInTwoWayBindings: true,
984+
checkTwoWayBoundEvents: true,
984985
};
985986

986987
describe('config.applyTemplateContextGuards', () => {

packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ export const ALL_ENABLED_CONFIG: Readonly<TypeCheckingConfig> = {
284284
controlFlowPreventingContentProjection: 'warning',
285285
unusedStandaloneImports: 'warning',
286286
allowSignalsInTwoWayBindings: true,
287+
checkTwoWayBoundEvents: true,
287288
};
288289

289290
// Remove 'ref' from TypeCheckableDirectiveMeta and add a 'selector' instead.
@@ -423,6 +424,7 @@ export function tcb(
423424
useInlineTypeConstructors: true,
424425
suggestionsForSuboptimalTypeInference: false,
425426
allowSignalsInTwoWayBindings: true,
427+
checkTwoWayBoundEvents: true,
426428
...config,
427429
};
428430
options = options || {

packages/compiler-cli/test/ngtsc/authoring_inputs_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ runInEachFileSystem(() => {
2121

2222
beforeEach(() => {
2323
env = NgtscTestEnvironment.setup(testFiles);
24-
env.tsconfig({strictTemplates: true});
24+
env.tsconfig({strictTemplates: true, _checkTwoWayBoundEvents: true});
2525
});
2626

2727
it('should handle a basic, primitive valued input', () => {

packages/compiler-cli/test/ngtsc/authoring_models_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ runInEachFileSystem(() => {
2121

2222
beforeEach(() => {
2323
env = NgtscTestEnvironment.setup(testFiles);
24-
env.tsconfig({strictTemplates: true});
24+
env.tsconfig({strictTemplates: true, _checkTwoWayBoundEvents: true});
2525
});
2626

2727
it('should declare an input/output pair for a field initialized to a model()', () => {

packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ runInEachFileSystem(() => {
544544
});
545545

546546
it('should type check a two-way binding to a generic property', () => {
547-
env.tsconfig({strictTemplates: true});
547+
env.tsconfig({strictTemplates: true, _checkTwoWayBoundEvents: true});
548548
env.write(
549549
'test.ts',
550550
`
@@ -582,7 +582,7 @@ runInEachFileSystem(() => {
582582
});
583583

584584
it('should use the setter type when assigning using a two-way binding to an input with different getter and setter types', () => {
585-
env.tsconfig({strictTemplates: true});
585+
env.tsconfig({strictTemplates: true, _checkTwoWayBoundEvents: true});
586586
env.write(
587587
'test.ts',
588588
`
@@ -618,7 +618,7 @@ runInEachFileSystem(() => {
618618
});
619619

620620
it('should type check a two-way binding to a function value', () => {
621-
env.tsconfig({strictTemplates: true});
621+
env.tsconfig({strictTemplates: true, _checkTwoWayBoundEvents: true});
622622
env.write(
623623
'test.ts',
624624
`
@@ -658,7 +658,7 @@ runInEachFileSystem(() => {
658658
});
659659

660660
it('should type check a two-way binding to input/output pair where the input has a wider type than the output', () => {
661-
env.tsconfig({strictTemplates: true});
661+
env.tsconfig({strictTemplates: true, _checkTwoWayBoundEvents: true});
662662
env.write(
663663
'test.ts',
664664
`
@@ -3007,7 +3007,7 @@ runInEachFileSystem(() => {
30073007
});
30083008

30093009
it('should type check a two-way binding to an input with a transform', () => {
3010-
env.tsconfig({strictTemplates: true});
3010+
env.tsconfig({strictTemplates: true, _checkTwoWayBoundEvents: true});
30113011
env.write(
30123012
'test.ts',
30133013
`

0 commit comments

Comments
 (0)