Angular 类接口函数定义-类型错误:对象不';不支持属性或方法

Angular 类接口函数定义-类型错误:对象不';不支持属性或方法,angular,typescript,typescript2.0,Angular,Typescript,Typescript2.0,我在Angular应用程序中编写了一个类似于以下内容的构造(为了演示这个问题,已经对其进行了极大的简化)。什么会阻止在DemoSource类中的项实例上定义filterProperty()函数 export关键字被使用,因为每个构造都在一个单独的文件中定义。 export interface IProperty { filterProperty(): string; } export class Demo implements IProperty { displayName:

我在Angular应用程序中编写了一个类似于以下内容的构造(为了演示这个问题,已经对其进行了极大的简化)。什么会阻止在
DemoSource
类中的
实例上定义
filterProperty()
函数

export
关键字被使用,因为每个构造都在一个单独的文件中定义。

export interface IProperty {
    filterProperty(): string;
}

export class Demo implements IProperty {
    displayName: string;

    filterProperty(): string {
        return this.displayName;
    }
}

export class DemoSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];

    constructor(private service: IService<TItem>) {
        // A BehaviorSubject<Array<TItem>> from a service
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        return Observable.merge(this.service.data).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                // Object doesn't support property or method 'filterProperty'
                const searchStr = item.filterProperty().toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
下面是使用API中的数据填充的服务:

以下是来自浏览器的纯API调用的结果:

某些属性因其数据而被修订

更新-传输的JavaScript

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
更新
演示问题的Web应用程序:

Web应用程序的GitHub Repo:

,因为我认为
过滤器
是保留关键字。因此,尝试在类型
对象
上实现
过滤器
函数<代码>过滤器
只能用于
阵列
。尝试为函数使用不同的名称

如果不是这样的话。也许服务数据项应该作为
Object
而不是
TTem
实例出现。我们只能在其实例上获得类方法。您可以尝试如下创建新实例吗

this.filteredData = this.service.data.value.slice().filter(
(item: TItem) => {
            // Object doesn't support property or method 'filter'
            let instance: TItem = new TItem();
            Object.assign(instance, item);
            const searchStr = instance.filter().toLowerCase();
            return searchStr.indexOf(this.filter.toLowerCase()) !==-1;
        });

我认为,
filter
是保留关键字。因此,尝试在类型
对象
上实现
过滤器
函数<代码>过滤器
只能用于
阵列
。尝试为函数使用不同的名称

如果不是这样的话。也许服务数据项应该作为
Object
而不是
TTem
实例出现。我们只能在其实例上获得类方法。您可以尝试如下创建新实例吗

this.filteredData = this.service.data.value.slice().filter(
(item: TItem) => {
            // Object doesn't support property or method 'filter'
            let instance: TItem = new TItem();
            Object.assign(instance, item);
            const searchStr = instance.filter().toLowerCase();
            return searchStr.indexOf(this.filter.toLowerCase()) !==-1;
        });

我能够让它工作的方式,我原本希望它与下面的设置。很显然,关键在于向C#对象添加一个
filter
属性,该对象用于通过Web API将数据序列化为JSON。不确定为什么需要这样做,因为TypeScript应该能够使用附加功能扩展从Web API接收的模型

简化示例以演示问题集

DemoModel.cs

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
iproperty.interface.ts

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
demo.model.ts

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
core.datasource.ts

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
导出类CoreDataSource{
filterChange=新行为主体(“”);
过滤数据:滴度[];
get filter():字符串{返回this.filterChange.value;}
设置过滤器(过滤器:字符串){this.filterChange.next(过滤器);}
建造商(私人服务:iSeries){
超级();
this.filteredData=service.data.value.slice();
}
connect():可观察{
const displayDataChanges=[
这个服务数据,
这是我的过滤器更换
];
返回可观察的.merge(…displayDataChanges).map(()=>{
this.filteredData=this.service.data.value.slice().filter((项:TItem)=>{
const searchStr=item.filter.toLowerCase();
返回searchStr.indexOf(this.filter.toLowerCase())!=-1;
});
返回过滤器数据;
});
}
}

通过下面的设置,我可以让它以我最初希望的方式工作。很显然,关键在于向C#对象添加一个
filter
属性,该对象用于通过Web API将数据序列化为JSON。不确定为什么需要这样做,因为TypeScript应该能够使用附加功能扩展从Web API接收的模型

简化示例以演示问题集

DemoModel.cs

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
iproperty.interface.ts

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
demo.model.ts

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
core.datasource.ts

Object.defineProperty(exports, "__esModule", { value: true });
var Demo = (function () {
    function Demo() {}
    Object.defineProperty(Demo.prototype, "filter", {
        get: function () { return this.displayName; },
        enumerable: true,
        configurable: true
    });
    return Demo;
}());
exports Demo = Demo;
// C# Class JSON is serialized from via Web API
public class DemoModel
{
    public string displayName { get; set; }
    public string filter
    {
        get { return displayName; }
    }
}
export interface IProperty {
    filter: string;
}
import { IProperty } from '../interfaces/iproperty.interface';

export class Demo implements IProperty {
    displayName: string;
    get filter(): string { return this.displayName; }
}
export class CoreDataSource<TItem extends IProperty> {
    filterChange = new BehaviorSubject('');
    filteredData: TItem[];
    get filter(): string { return this.filterChange.value; }
    set filter(filter: string) { this.filterChange.next(filter); }

    constructor(private service: IService<TItem>) {
        super();
        this.filteredData = service.data.value.slice();
    }

    connect(): Observable<TItem[]> {
        const displayDataChanges = [
            this.service.data,
            this.filterChange
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            this.filteredData = this.service.data.value.slice().filter((item: TItem) => {
                const searchStr = item.filter.toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
            });

            return filteredData;
        });
    }
}
导出类CoreDataSource{
filterChange=新行为主体(“”);
过滤数据:滴度[];
get filter():字符串{返回this.filterChange.value;}
设置过滤器(过滤器:字符串){this.filterChange.next(过滤器);}
建造商(私人服务:iSeries){
超级();
this.filteredData=service.data.value.slice();
}
connect():可观察{
const displayDataChanges=[
这个服务数据,
这是我的过滤器更换
];
返回可观察的.merge(…displayDataChanges).map(()=>{
this.filteredData=this.service.data.value.slice().filter((项:TItem)=>{
const searchStr=item.filter.toLowerCase();
返回searchStr.indexOf(this.filter.toLowerCase())!=-1;
});
返回过滤器数据;
});
}
}

数据是JSON响应的结果,是一种普通对象和数组的结构,这些对象和数组只有在原型上定义的方法,
对象和
数组

item
实际上不是一个类实例,也没有它应该具有的
filterProperty
方法。因此,指定
DemoSource
是不正确的,因为
IProperty
应该具有
filterProperty
。这愚弄了TypeScript,使其认为对象有这个方法,而它们没有——它们仍然是普通对象,指定的类型不会改变它们

用于泛型的接口应该反映数据结构属性(而不是方法)。对于应该由普通对象构造的类,最好在构造函数中接受普通对象:

export interface IItemData {
    displayName: string;
    id?: number;
    ...
}

export class Item implements IItemData {
    displayName: string;

    constructor({ displayName }: IItemData) {
        this.displayName = displayName;
    }

    filterProperty(): string {
        return this.displayName;
    }
}
然后应处理数据结构,并将普通项转换为
实例:

export class DemoSource<TItem extends IItemData> {
    ...
    this.filteredData = this.service.data.value.slice()
    .map((item: TItem) => {
        // item doesn't have 'filterProperty'
        return new Item(item); 
    })
    .filter((item: Item) => {
        // item has 'filterProperty'
        const searchStr = item.filterProperty().toLowerCase();
        return searchStr.indexOf(this.filter.toLowerCase()) !== -1;
    });
    ...
导出类DemoSource{
...
this.filteredData=this.service.data.value.slice()
.map((项目:TItem)=>{
//项目没有“filterProperty”
返回新项目(项目);
})
菲菲先生