mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(core): Allow other expression for exhaustive typechecking
When the switched expression is nested within a union, exhaustive typechecking needs to know which expression to check.
This change adds the possibility of specifying the expression to check:
```
@Component({
selector: 'app-root',
imports: [],
template: `
@switch (state.mode) {
@case ('show') { {{ state.menu }}; }
@case ('hide') {}
@default never(state);
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class App {
state!: { mode: 'hide' } | { mode: 'show'; menu: number };;
}
```
fixes #67406
This commit is contained in:
committed by
Leon Senft
parent
0eeb1b5f03
commit
8bc31a515f
@@ -60,7 +60,12 @@ export class TcbSwitchOp extends TcbOp {
|
||||
});
|
||||
|
||||
if (this.block.exhaustiveCheck) {
|
||||
const switchValue = tcbExpression(this.block.expression, this.tcb, this.scope);
|
||||
let translateExpression = this.block.expression;
|
||||
if (this.block.exhaustiveCheck.expression) {
|
||||
translateExpression = this.block.exhaustiveCheck.expression;
|
||||
}
|
||||
|
||||
const switchValue = tcbExpression(translateExpression, this.tcb, this.scope);
|
||||
const exhaustiveId = this.tcb.allocateId();
|
||||
|
||||
clauses.push(
|
||||
|
||||
@@ -1453,6 +1453,25 @@ class TestComponent {
|
||||
|
||||
expect(messages).toEqual([]);
|
||||
});
|
||||
|
||||
it('should narrow union when switching on a nested prop', () => {
|
||||
const messages = diagnose(
|
||||
`
|
||||
@switch (state.mode) {
|
||||
@case ('show') { {{ state.menu }}; }
|
||||
@case ('hide') {}
|
||||
@default never(state);
|
||||
}
|
||||
`,
|
||||
`
|
||||
export class TestComponent {
|
||||
state: { mode: 'hide' } | { mode: 'show'; menu: number };
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
expect(messages).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/angular/angular/issues/43970
|
||||
|
||||
@@ -2202,6 +2202,27 @@ describe('type check blocks', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should generate a switch block with exhaustiveness checking with param', () => {
|
||||
const TEMPLATE = `
|
||||
@switch (expr) {
|
||||
@case (1) {
|
||||
{{one()}}
|
||||
}
|
||||
@case (2) {
|
||||
{{two()}}
|
||||
}
|
||||
@default never(expr.prop);
|
||||
}
|
||||
`;
|
||||
|
||||
expect(tcb(TEMPLATE)).toContain(
|
||||
'switch (((this).expr)) { ' +
|
||||
'case 1: "" + ((this).one()); break; ' +
|
||||
'case 2: "" + ((this).two()); break; ' +
|
||||
'default: const tcbExhaustive_t1: never = ((((this).expr)).prop);',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not report unused locals for exhaustiveness check variable', () => {
|
||||
const TEMPLATE = `
|
||||
@switch (expr) {
|
||||
|
||||
Reference in New Issue
Block a user