[英]Typescript with Angular HttpClient ErrorType ... is not a function when calling class method
I'm facing some weird (to me) problem with objects and types in typescript/angular.我在 typescript/angular 中遇到了一些奇怪的(对我来说)对象和类型的问题。
I have some class describing my objects received from remote API:我有一些类描述从远程 API 接收到的对象:
export class Point {
lat:number;
lng:number;
name:string;
public doSomething() {
console.log("doSomething called");
}
}
I'm using HttpClient
to get objects from API:我正在使用
HttpClient
从 API 获取对象:
constructor(private http:HttpClient) {}
getPointsAsync(callback: (points: Point[]) => {}) {
this.http.get<Point[]>(`${environment.apiUrl}/api/points`)
.subscribe(
(result: Point[]) => {
//do something with data
callback(result);
},
error => { //some error handling
}
);
}
My problem is that when I try to call method doSomething
on one of my Point from array我的问题是,当我尝试从数组中的一个点上调用方法
doSomething
var firstPoint = points[0];
firstPoint.doSomething()
I get some weird error on console:我在控制台上收到一些奇怪的错误:
ERROR TypeError: firstPoint.doSomething is not a function
I'm not using Typescript and Angular for very long so I'm assuming that it is something wrong with my code but I couldn't find answer to my issue.我很久没有使用 Typescript 和 Angular,所以我假设我的代码有问题,但我找不到问题的答案。 Could you give me some advice?
你能给我一些建议吗?
The problem is that you don' actually get instances of Point<\/code> from the web service.
问题是您实际上并没有从 Web 服务中获取
Point<\/code>的实例。
You get a JSON object that has the class fields, but not the methods.
你得到一个 JSON 对象,它有类字段,但没有方法。 You can use instantiate the class and use
Object.assign<\/code> to assign the values from the object literal to each
Point<\/code> instance
您可以使用实例化类并使用
Object.assign<\/code>将对象文字中的值分配给每个
Point<\/code>实例
getPointsAsync(callback: (points: Partial<Point>[]) => {}) {
this.http.get<Point[]>(`${environment.apiUrl}/api/points`)
.subscribe(
(result: Partial<Point>[]) => {
let points = result.map(p=> Object.assign(new Point(), p));
callback(points);
},
error => { //some error handling
}
);
}
Object.assign()<\/code> will solve your current problem, but not if you have nested objects.
Object.assign()<\/code>将解决您当前的问题,但如果您有嵌套对象,则不会。
Then you will have to do
Object.assign()<\/code> for each nested object as well, which can get tedious if you have to do this in multiple places in your codebase.
然后,您还必须为每个嵌套对象执行
Object.assign()<\/code> ,如果您必须在代码库的多个位置执行此操作,这可能会变得乏味。
I suggest an alternative: class-transformer<\/a> With this you can mark your nested fields with annotations that tell the compiler how to create the nested objects as well.我建议一个替代方案:
class-transformer<\/a>使用它,您可以使用注释标记嵌套字段,这些注释告诉编译器如何创建嵌套对象。 With this you only need to use the
plainToClass()<\/code> method to map your top level object and all the underlying fields will also have the correct types\/objects.
有了这个,您只需要使用
plainToClass()<\/code>方法来映射您的顶级对象,所有底层字段也将具有正确的类型\/对象。
Example例子<\/h2>Let's say we have two classes:
假设我们有两个类:
![](/img/trans.png)
class Parent { name: string; child: Child; public getText(): string { return 'parent text'; } } class Child{ name: string; public getText(): string { return 'child text'; } }<\/code><\/pre> The first case<\/strong> we already know doesn't work:我们已经知道的第一种情况<\/strong>不起作用:
let parentJson: any = {name: 'parent name', child: {name: 'child name'}}; let parent: Parent = parentJson; \/\/ note: compiler accepts this because parentJson is any. \/\/ If we tried to assign the json structure directly to 'parent' it would fail because the compiler knows that the method getText() is missing! console.log(parent.getText()); \/\/ throws the error that parent.getText() is not a function as expected<\/code><\/pre> Second case<\/strong> using Object.assign()<\/code> :
使用Object.assign()<\/code>第二种情况<\/strong>:
![](/img/trans.png)
let parentJson: any = {name: 'parent name', child: {name: 'child name'}}; let parent: Parent = Object.assign(parentJson); console.log(parent.getText()); \/\/ this works console.log(parent.child.getText()); \/\/ throws error that parent.child.getText() is not a function!<\/code><\/pre> to make it work, we would have to do the following:为了使其工作,我们必须执行以下操作:
let parentJson: any = {name: 'parent name', child: {name: 'child name'}}; let parent: Parent = Object.assign(parentJson); parent.child = Object.assign(parentJson.child); console.log(parent.getText()); \/\/ this works console.log(parent.child.getText()); \/\/ this works<\/code><\/pre> Third case<\/strong> with class-transformer:使用类转换器的第三种情况<\/strong>:
First modify the parent class so that the child mapping is defined:首先修改父类,以便定义子映射:
class Parent { name: string; @Type(() => Child) child: Child; public getText(): string { return 'parent text'; } }<\/code><\/pre> then you can map to the parent object:然后你可以映射到父对象:
let parentJson: any = {name: 'parent name', child: {name: 'child name'}}; let parent: Parent = plainToClass(Parent, parentJson); console.log(parent.getText()); \/\/ this works console.log(parent.child.getText()); \/\/ this works<\/code><\/pre>"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.