fix(language-service): infer context type of structural directives (#35537) (#35561)

PR Close #35561
This commit is contained in:
Pusztai Tibor
2020-02-19 20:38:21 +01:00
committed by Miško Hevery
parent bd6a39c364
commit 54fd33fb80
4 changed files with 98 additions and 41 deletions

View File

@ -286,6 +286,42 @@ describe('diagnostics', () => {
expect(start).toBe(span.start);
expect(length).toBe(span.length);
});
it('report an unknown field in $implicit context', () => {
mockHost.override(TEST_TEMPLATE, `
<div *withContext="let myVar">
{{ ~{start-emb}myVar.missingField ~{end-emb}}}
</div>
`);
const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE);
expect(diags.length).toBe(1);
const {messageText, start, length, category} = diags[0];
expect(category).toBe(ts.DiagnosticCategory.Error);
expect(messageText)
.toBe(
`Identifier 'missingField' is not defined. '{ implicitPerson: Person; }' does not contain such a member`, );
const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb');
expect(start).toBe(span.start);
expect(length).toBe(span.length);
});
it('report an unknown field in non implicit context', () => {
mockHost.override(TEST_TEMPLATE, `
<div *withContext="let myVar = nonImplicitPerson">
{{ ~{start-emb}myVar.missingField ~{end-emb}}}
</div>
`);
const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE);
expect(diags.length).toBe(1);
const {messageText, start, length, category} = diags[0];
expect(category).toBe(ts.DiagnosticCategory.Error);
expect(messageText)
.toBe(
`Identifier 'missingField' is not defined. 'Person' does not contain such a member`, );
const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb');
expect(start).toBe(span.start);
expect(length).toBe(span.length);
});
});
// #17611

View File

@ -43,6 +43,7 @@ import * as ParsingCases from './parsing-cases';
ParsingCases.StringModel,
ParsingCases.TemplateReference,
ParsingCases.TestComponent,
ParsingCases.WithContextDirective,
]
})
export class AppModule {

View File

@ -127,6 +127,21 @@ export class CounterDirective implements OnChanges {
}
}
interface WithContextDirectiveContext {
$implicit: {implicitPerson: Person;};
nonImplicitPerson: Person;
}
@Directive({selector: '[withContext]'})
export class WithContextDirective {
constructor(_template: TemplateRef<WithContextDirectiveContext>) {}
static ngTemplateContextGuard(dir: WithContextDirective, ctx: unknown):
ctx is WithContextDirectiveContext {
return true;
}
}
/**
* This Component provides the `test-comp` selector.
*/