我在Angular应用程序中编写了类似于以下内容的构造(这已经大大简化以演示问题)。什么会阻止在filterProperty()
类的item
实例中定义DemoSource
函数?
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;
});
}
}
在调用item.filter()
时进行调试时,出现以下错误:
ERROR TypeError: Object doesn't support property or method 'filterProperty'
更新
已将IProperty
合同函数从filter()
更改为filterProperty()
以避免混淆。
这是错误:
在这里,您可以看到item
实例如何正确填充其所有属性,但未定义filterProperty()
函数(它不在 proto 中或者):
更新
以下是服务详情:
@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>;
}
某些属性因其数据而被编辑
更新 - 透明的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演示此问题:Typescript / Web API Interface Issue
Web应用程序的GitHub Repo:typescript-interface-issues
答案 0 :(得分:3)
来自JSON响应的数据结果,是纯对象和数组的结构,只有在其原型var whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { query.ElementType },
query.Expression,
Expression.Quote(lambda));
和Object
上定义的方法。
Array
不是一个真正的类实例,并且它没有item
方法。因此,考虑到filterProperty
应该具有DemoSource<IProperty>
,指定IProperty
是不正确的。这使得TypeScript认为对象有这种方法,而他们没有这种方法 - 它们仍然是普通的对象,指定的类型不会改变它们。
用于泛型的接口应该反映数据结构属性(而不是方法)。对于应该由普通对象构造的类,在构造函数中接受普通对象是一种很好的做法:
filterProperty
然后应该处理数据结构,并且应该将普通项转换为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
答案 1 :(得分:0)
我认为filter
是保留关键字。因此,角度尝试在filter
类型上实现Object
函数。 filter
只能用于Array
。尝试为函数使用不同的名称。
如果不是这样的话。也许服务数据项应该是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;
});
答案 2 :(得分:0)
我能够按照我原先想要的方式使用以下设置。显然,关键是向C#对象添加filter
属性,该对象用于通过Web API将数据序列化为JSON。不确定为什么需要这样做,因为TypeScript应该能够扩展从Web API接收的模型以及其他功能。
示例简化以演示问题集
DemoModel.cs
// C# Class JSON is serialized from via Web API
public class DemoModel
{
public string displayName { get; set; }
public string filter
{
get { return displayName; }
}
}
iproperty.interface.ts
export interface IProperty {
filter: string;
}
demo.model.ts
import { IProperty } from '../interfaces/iproperty.interface';
export class Demo implements IProperty {
displayName: string;
get filter(): string { return this.displayName; }
}
core.datasource.ts
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;
});
}
}