angular: Generics do not correctly infer in template pipe usage

I’m submitting a…


[x] Bug report  

Current behavior

Please take a look at the minimal example below:

@Pipe({name: 'map'})
export class MapPipe implements PipeTransform {
  transform<T, R>(value: T[], func: (value: T) => R): R[] {
    return value ? value.map(func) : [];
  }
}

// the component
interface InData {
  foo: string;
}

interface OutData {
  bar: string;
}

@Component({
  selector: 'app-test',
  template: `
    <span *ngFor="let item of items | map: _mapper">
      {{item.bar}}
    </span>
  `,
})
export class TestComponent {
  @Input() items: InData[];

  _mapper(item: InData): OutData {
    return {
      bar: item.foo,
    };
  }
}

Angular language service (v5.0.2) gives me an error: Error:(7, 9) Angular: Identifier 'bar' is not defined. 'R' does not contain such a member

Expected behavior

Should infer the type as TypeScript would.

From https://github.com/angular/vscode-ng-language-service/issues/196

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 43
  • Comments: 28 (7 by maintainers)

Most upvoted comments

The Ivy Language Service is currently under construction. I pasted this example into a running IDE with it.

We’re able to infer the generic arguments to MapPipe.transform:

Screen Shot 2020-10-20 at 1 17 18 PM

which flows through to the type of item in the *ngFor:

Screen_Shot_2020-10-20_at_1 18 58_PM

@kyliau Angular10 landed, is there update?

Any news? I’m using vscode extension and its basically unusable. A lot of errors everywhere.

I am having same issue with built-in slice pipe.

For instance:

<div *ngFor="let item of (items | slice : 0 : 5)">

The type of item is lost. item.id starts giving error:

Identifier 'id' is not defined. 'T' does not contain such a member"

Would love to see a fix or workaround for this. Let us know if we can help. I thought I had made a mistake fixing up my template variable types. I didn’t notice it was compiling despite the warnings in VS Code.

It is almost 2 years after this bug is first added and still with Angular 8.2.7 this issue is not fixed. I do understand that TypeScript 3 may have an issue with this, but i also think that the Angular Pipe should have a solution for this. It is not always possible or wanted to do stuff like slining outsite of the template. otherwise i could do some like this.trips = this.trips.slice(this.start,this.end);

@dylansteen The language service currently does not look at angularCompilerOptions, so it’ll not have any effect. We’re already working on the language service for v10 which will support that fullTemplateTypeCheck flag.

one thing thats driving me crazy is why does it work for angular’s native pipes? https://github.com/angular/angular/blob/master/packages/common/src/pipes/async_pipe.ts

For the sake of completeness, here’s a keypipe demo of the issue:

Using the keyvalue pipe throws errors in template.

Identifier 'myProperty' is not defined. 'V' does not contain such a member. (ng)

app.component.html

<ul>
  <li *ngFor="let entry of menuService.menu | keyvalue">
    <span>{{ entry.value.text }}</span>
  </li>
</ul>

menu-items.model.ts

export interface MenuItem {
  text: string;
}

export interface Menu {
  [key: string]: MenuItem;
}

Other (Snippets):

// app.component.ts
import { MenuService } from './menu-items/menu-items.service';
export class AppComponent {
  constructor(public menuService: MenuService) {}
}

// menu-items.service.ts
import { Menu, MenuItem } from './menu-items.model';
public menu: Menu = {};
// See model (above).

demo (Gif Animation. Wait for the first frame in app.component.html)

Download Demo Project

See more about this in the referenced issues. Including versions etc. (since v11-next.4, We have to use this version. We cannot go back to v10.) I hope for a higher priority to fix this as soon as possible. Is it possible to disable language service for this type checking? It’s better than pseudo errors. This could be a hotfix for the very next release this days. I don’t want to disable the whole plugin.

why can’t we use something like this? *ngFor=“let image of imageList | sortBy<OurType>”

Unfortunately, that is invalid Angular syntax today (expressions cannot have generics). The most viable use case would likely be just for this issue, so I do not think this syntax would be introduced.

Any ideas on this? I’m running across this with the slice pipe as well.

Same for webstorm

I don’t believe this is fully resolved. I have a generic sort pipe which starts with the following:

transform<T>(arr: T[], prop: string, reverse: boolean = false): T[] {

However I still get the error Identifier 'sort' is not defined. 'T' does not contain such a member within my templates, this is an example implementation, the image.sort is showing the error:

<li *ngFor="let image of imageList | sortBy : 'sort'">
    <div>{{image.sort}}</div>
</li>

This is the versioning output from the extension:

[Info  - 10:55:06] Using typescript v3.6.4 from c:\Users\bensh\.vscode\extensions\angular.ng-template-0.900.4\node_modules\typescript\lib\tsserverlibrary.js
[Info  - 10:55:06] Using @angular/language-service v9.0.0-rc.8 from c:\Users\bensh\.vscode\extensions\angular.ng-template-0.900.4\server\node_modules\@angular\language-service\bundles\language-service.umd.js