You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: packages/compiler-cli/src/ngtsc/typecheck/README.md
+30-30Lines changed: 30 additions & 30 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,7 +24,7 @@ TCBs are not ever emitted, nor are they referenced from any other code (they're
24
24
Given a component `SomeCmp`, its TCB takes the form of a function:
25
25
26
26
```typescript
27
-
function tcb(ctx:SomeCmp):void {
27
+
function tcb(this:SomeCmp):void {
28
28
// TCB code
29
29
}
30
30
```
@@ -38,15 +38,15 @@ The component context is the theoretical component instance associated with the
38
38
39
39
For example, if `SomeCmp`'s template has an interpolation expression `{{foo.bar}}`, this suggests that `SomeCmp` has a property `foo`, and that `foo` itself is an object with a property `bar` (or in a type sense, that the type of `SomeCmp.foo` has a property `bar`).
40
40
41
-
Such a binding is expressed in the TCB function, using the `ctx` parameter as the component instance:
41
+
Such a binding is expressed in the TCB function, using the `this` parameter as the component instance:
42
42
43
43
```typescript
44
-
function tcb(ctx:SomeCmp):void {
45
-
''+ctx.foo.bar;
44
+
function tcb(this:SomeCmp):void {
45
+
''+this.foo.bar;
46
46
}
47
47
```
48
48
49
-
If `SomeCmp` does not have a `foo` property, then TypeScript will produce a type error/diagnostic for the expression `ctx.foo`. If `ctx.foo` does exist, but is not of a type that has a `bar` property, then TypeScript will catch that too. By mapping the template expression `{{foo.bar}}` to TypeScript code, the compiler has captured its _intent_ in the TCB in a way that TypeScript can validate.
49
+
If `SomeCmp` does not have a `foo` property, then TypeScript will produce a type error/diagnostic for the expression `this.foo`. If `this.foo` does exist, but is not of a type that has a `bar` property, then TypeScript will catch that too. By mapping the template expression `{{foo.bar}}` to TypeScript code, the compiler has captured its _intent_ in the TCB in a way that TypeScript can validate.
50
50
51
51
#### Types of template declarations
52
52
@@ -62,7 +62,7 @@ declares a single `<input>` element with a local ref `#name`, meaning that withi
62
62
Within the TCB, the `<input>` element is treated as a declaration, and the compiler leverages the powerful type inference of `document.createElement`:
63
63
64
64
```typescript
65
-
function tcb(ctx:SomeCmp):void {
65
+
function tcb(this:SomeCmp):void {
66
66
var _t1 =document.createElement('input');
67
67
''+_t1.value;
68
68
}
@@ -83,13 +83,13 @@ Just like with HTML elements, directives present on elements within the template
83
83
The TCB for this template looks like:
84
84
85
85
```typescript
86
-
function tcb(ctx:SomeCmp):void {
86
+
function tcb(this:SomeCmp):void {
87
87
var _t1:OtherCmp=null!;
88
-
_t1.foo=ctx.bar;
88
+
_t1.foo=this.bar;
89
89
}
90
90
```
91
91
92
-
Since `<other-cmp>` is a component, the TCB declares `_t1` to be of that component's type. This allows for the binding `[foo]="bar"` to be expressed in TypeScript as `_t1.foo = ctx.bar` - an assignment to `OtherCmp`'s `@Input` for `foo` of the `bar` property from the template's context. TypeScript can then type check this operation and produce diagnostics if the type of `ctx.bar` is not assignable to the `_t1.foo` property which backs the `@Input`.
92
+
Since `<other-cmp>` is a component, the TCB declares `_t1` to be of that component's type. This allows for the binding `[foo]="bar"` to be expressed in TypeScript as `_t1.foo = this.bar` - an assignment to `OtherCmp`'s `@Input` for `foo` of the `bar` property from the template's context. TypeScript can then type check this operation and produce diagnostics if the type of `this.bar` is not assignable to the `_t1.foo` property which backs the `@Input`.
93
93
94
94
#### Generic directives & type constructors
95
95
@@ -147,9 +147,9 @@ This type constructor can then be used to infer the instance type of a usage of
147
147
Would use the above type constructor in its TCB:
148
148
149
149
```typescript
150
-
function tcb(ctx:SomeCmp):void {
151
-
var _t1 =ctor1({ngForOf: ctx.users});
152
-
// Assuming ctx.users is User[], then _t1 is inferred as NgFor<User>.
150
+
function tcb(this:SomeCmp):void {
151
+
var _t1 =ctor1({ngForOf: this.users});
152
+
// Assuming this.users is User[], then _t1 is inferred as NgFor<User>.
153
153
}
154
154
```
155
155
@@ -180,9 +180,9 @@ In the TCB, the template context of this nested template is itself a declaration
// _t1 is the NgFor directive instance, inferred as NgFor<User>.
226
-
var _t1 =ctor1({ngForOf: ctx.users});
226
+
var _t1 =ctor1({ngForOf: this.users});
227
227
228
228
// _t2 is the context type for the embedded views created by the NgFor structural directive.
229
229
var _t2:any;
@@ -258,15 +258,15 @@ Because the `NgFor` directive _declared_ to the template type checking engine wh
258
258
Obviously, if `user` is potentially `null`, then this `NgIf` is intended to only show the `<div>` when `user` actually has a value. However, from a type-checking perspective, the expression `user.name` is not legal if `user` is potentially `null`. So if this template was rendered into a TCB as:
259
259
260
260
```typescript
261
-
function tcb(ctx:SomeCmp):void {
261
+
function tcb(this:SomeCmp):void {
262
262
// Type of the NgIf directive instance.
263
263
var _t1:NgIf;
264
264
265
265
// Binding *ngIf="user != null".
266
-
_t1.ngIf=ctx.user!==null;
266
+
_t1.ngIf=this.user!==null;
267
267
268
268
// Nested template interpolation `{{user.name}}`
269
-
''+ctx.user.name;
269
+
''+this.user.name;
270
270
}
271
271
```
272
272
@@ -286,23 +286,23 @@ export class NgIf {
286
286
The presence and type of this static property tells the template type-checking engine to reflect the bound expression for its `ngIf` input as a guard for any embedded views created by the structural directive. This produces a TCB:
287
287
288
288
```typescript
289
-
function tcb(ctx:SomeCmp):void {
289
+
function tcb(this:SomeCmp):void {
290
290
// Type of the NgIf directive instance.
291
291
var _t1:NgIf;
292
292
293
293
// Binding *ngIf="user != null".
294
-
_t1.ngIf=ctx.user!==null;
294
+
_t1.ngIf=this.user!==null;
295
295
296
296
// Guard generated due to the `ngTemplateGuard_ngIf` declaration by the NgIf directive.
297
297
if (user!==null) {
298
298
// Nested template interpolation `{{user.name}}`.
299
-
// `ctx.user` here is appropriately narrowed to be non-nullable.
300
-
''+ctx.user.name;
299
+
// `this.user` here is appropriately narrowed to be non-nullable.
300
+
''+this.user.name;
301
301
}
302
302
}
303
303
```
304
304
305
-
The guard expression causes TypeScript to narrow the type of `ctx.user` within the `if` block and identify that `ctx.user` cannot be `null` within the embedded view context, just as `NgIf` itself does during rendering.
305
+
The guard expression causes TypeScript to narrow the type of `this.user` within the `if` block and identify that `this.user` cannot be `null` within the embedded view context, just as `NgIf` itself does during rendering.
306
306
307
307
### Generation process
308
308
@@ -393,7 +393,7 @@ Here, type-checking the `[in]` binding requires knowing the type of `ref`, which
// Generated to break the cycle for `ref` - infers a placeholder
413
413
// type for the component without using any of its input bindings.
414
414
var t1 =ctor1(null!);
@@ -445,16 +445,16 @@ Consider a template expression of the form:
445
445
The generated TCB code for this expression would look like:
446
446
447
447
```typescript
448
-
''+ctx.foo.bar;
448
+
''+this.foo.bar;
449
449
```
450
450
451
451
What actually gets generated for this expression looks more like:
452
452
453
453
```typescript
454
-
''+ (ctx.foo/* 3,5 */).bar/* 3,9 */;
454
+
''+ (this.foo/* 3,5 */).bar/* 3,9 */;
455
455
```
456
456
457
-
The trailing comment for each node in the TCB indicates the template offsets for the corresponding template nodes. If for example TypeScript returns a diagnostic for the `ctx.foo` part of the expression (such as if `foo` is not a valid property on the component context), the attached comment can be used to map this diagnostic back to the original template's `foo` node.
457
+
The trailing comment for each node in the TCB indicates the template offsets for the corresponding template nodes. If for example TypeScript returns a diagnostic for the `this.foo` part of the expression (such as if `foo` is not a valid property on the component context), the attached comment can be used to map this diagnostic back to the original template's `foo` node.
458
458
459
459
#### `TemplateId`
460
460
@@ -548,7 +548,7 @@ Additions of such inline type checking code have significant ramifications on th
548
548
A similar problem exists for generic components and the declaration of TCBs. A TCB function must also copy the generic bounds of its context component:
549
549
550
550
```typescript
551
-
function tcb<Textendsstring>(ctx:SomeCmp<T>):void {
551
+
function tcb<Textendsstring>(this:SomeCmp<T>):void {
0 commit comments