LLL LLL - 2 months ago 25
TypeScript Question

Typescript: method is undefined when implementing an interface

I have an interface

export interface IFilterable{
passesFilter(f : string, isFilter: boolean): boolean;
}


That I want to use to filter things in Angular2 pipe.
It's implemented like this:

import {IFilterable} from './i-filterable';
import {Contains} from '../helpers/pipe-helpers';

export class Server extends Dto implements IFilterable {
name: string;
hostname: string;
ips: string;
operatingSystem: string;
sitesCount: number;
databasesCount: number;

passesFilter(f: string, isFilter: boolean): boolean {
console.log('in server');
if (!f || f === '') return isFilter;
f = f.toLowerCase();

return Contains(this.name, f) ||
Contains(this.hostname, f) ||
Contains(this.ips, f) ||
Contains(this.operatingSystem, f);
}
}


Contains function being imported.

The pipe looks like this

import { Pipe, PipeTransform } from '@angular/core';
import {Contains} from '../helpers/pipe-helpers';
import {IFilterable} from '../models/i-filterable';

@Pipe({ name: 'serverFilter' })
export class ServerFilterPipe implements PipeTransform {
transform(values: IFilterable[], search: string, isFilter: boolean): IFilterable[] {
console.log(search + ' search' + isFilter + values);
return values.filter(value => {
console.log(value.passesFilter);
return value.passesFilter(search, isFilter)
});
}
}


The second console.log in the pipe prints undefined, and the one in passesFilter never even gets called. I also get en error

TypeError: setting a property that has only a getter


Am I doing something wrong, or are interfaces not really usable like that in TS?

Edit: Implementing same thing with an abstract class.

export abstract class Dto {
abstract passesFilter(f: string, isFilter: boolean): boolean;
}


Server

import {Dto} from './dto';
import {Contains} from '../helpers/pipe-helpers';

export class Server extends Dto {
name: string;
hostname: string;
ips: string;
operatingSystem: string;
sitesCount: number;
databasesCount: number;

passesFilter(f: string, isFilter: boolean): boolean {
console.log('in server');
if (!f || f === '') return isFilter;
f = f.toLowerCase();

return Contains(this.name, f) ||
Contains(this.hostname, f) ||
Contains(this.ips, f) ||
Contains(this.operatingSystem, f);
}
}


pipe

import { Pipe, PipeTransform } from '@angular/core';
import {Dto} from '../models/dto';

@Pipe({ name: 'serverFilter' })
export class ServerFilterPipe implements PipeTransform {
transform(values: Dto[], search: string, isFilter: boolean): Dto[] {
console.log(search + ' search' + isFilter + values);
return values.filter(value => {
console.log(value.passesFilter);
return value.passesFilter(search, isFilter)
});
}
}


pipe-helpers

export function Contains(val: string, cmp: string) {
return val ? val.toLowerCase().indexOf(cmp) >= 0 : false;
}

Answer

We don't see the input of your pipe.. maybe that values aren't from type IFilterable ?! anyway i would check values before using it.. maybe its undefined during first pipe round..

@Pipe({ name: 'serverFilter' })
export class ServerFilterPipe implements PipeTransform {
   transform(values: IFilterable[], search: string, isFilter: boolean): IFilterable[] {
      console.log(search + ' search' + isFilter + values);
      if (!values || !values.length) return []; // check that input !

      return values.filter(value => {
         if (!value || !value.passesFilter) return false; // check that value !

         console.log(value.passesFilter);
         return value.passesFilter(search, isFilter)
      });
   }
}

And a hint for you:

if (!f || f === '') return isFilter;

this check is redundant.. !'' is true.

UPDATE

Check this plunker: https://plnkr.co/edit/IhM4rKqD3VvEZVBdimzK?p=preview

Comments