类接口函数定义-TypeError:对象不支持属性或方法 [英] Class Interface function definition - TypeError: Object doesn't support property or method

查看:316
本文介绍了类接口函数定义-TypeError:对象不支持属性或方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在Angular应用程序中编写了类似于以下内容的构造(已大大简化,以演示该问题).是什么会阻止在DemoSource类内部的item实例上定义filterProperty()函数?

I've written a construct similar to the following in an Angular app (this has been greatly simplified to demonstrate the issue). What would prevent the filterProperty() function from being defined on the item instance inside of the DemoSource class?

export关键字是因为每个结构都在单独的文件中定义.

export keyword is used because each construct is defined in a separate file.

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;
        });
    }
}

在调用item.filter()的位置进行调试时,出现以下错误:

When debugging at the point where item.filter() is called, I get the following error:

ERROR TypeError: Object doesn't support property or method 'filterProperty'

更新
IProperty合同功能从filter()更改为filterProperty(),以避免混淆.

Update
Changed the IProperty contract function from filter() to filterProperty() to avoid confusion.

这是错误:

在这里,您可以看到item实例如何正确填充了其所有属性,但是没有定义filterProperty()函数(也未在 proto 中使用):

Here, you can see how the item instance has all of its properties properly populated, but has no filterProperty() function defined (it's not in proto either):

更新
服务详情如下:

Update
Here are the service details:

@Injectable()
export class IdentityService implements IService<AppUser> {
    users = new BehaviorSubject<Array<AppUser>>([]);
    public get data(): BehaviorSubject<AppUser[]> { return this.users; }
}

export interface IService<T> {
    data: BehaviorSubject<T>;
}

以下是使用API​​中的数据填充的服务:

Here is the service being populated with data from the API:

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

Here is the result of a pure API call from the browser:

某些属性由于其数据而被删除

更新-已转译的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;

更新
Web App演示了该问题:打字稿/Web API接口问题
Web应用程序的GitHub存储库: typescript-interface-issues

Update
Web App demonstrating the issue: Typescript / Web API Interface Issue
GitHub Repo for the Web App: typescript-interface-issues

推荐答案

数据来自JSON响应,是普通对象和数组的结构,仅具有在其原型ObjectArray上定义的方法.

Data results from JSON response and is a structure of plain objects and arrays that only have methods that are defined on their prototypes, Object and Array.

item并不是真正的类实例,并且没有应该具有的filterProperty方法.因此,考虑到IProperty应该具有filterProperty,因此指定DemoSource<IProperty>是不正确的.这使TypeScript误以为对象拥有此方法,而对象却没有此方法-它们仍然是普通对象,指定的类型不会更改它们.

item isn't really a class instance and doesn't have filterProperty method it's supposed to have. So it's incorrect to specify DemoSource<IProperty>, considering that IProperty is supposed to have filterProperty. This fools TypeScript into thinking that objects have this method, while they don't have it - they are still plain objects, specified types don't change them.

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

An interface that is used for generic is supposed to reflect data structure properties (not methods). For classes that are supposed to be constructed from plain objects it's a good practice to accept plain object in constructor:

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;
    }
}

然后应处理数据结构,并将普通项目转换为Item实例:

Then data structure should be processed and plain items should be converted to Item instances:

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;
    });
    ...

这篇关于类接口函数定义-TypeError:对象不支持属性或方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆