带有 Angular HttpClient ErrorType 的 Typescript ... 在调用 class 方法时不是函数
Typescript with Angular HttpClient ErrorType ... is not a function when calling class method
我在 typescript/angular.
中遇到对象和类型的一些奇怪的(对我来说)问题
我有一些 class 描述了我从远程接收的对象 API:
export class Point {
lat:number;
lng:number;
name:string;
public doSomething() {
console.log("doSomething called");
}
}
我正在使用 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
}
);
}
我的问题是,当我尝试在数组
中的一个点上调用方法 doSomething
时
var firstPoint = points[0];
firstPoint.doSomething()
我在控制台上收到一些奇怪的错误:
ERROR TypeError: firstPoint.doSomething is not a function
我很长时间没有使用 Typescript 和 Angular,所以我假设我的代码有问题,但我找不到问题的答案。你能给我一些建议吗?
问题是您实际上并没有从 Web 服务中获取 Point
的实例。你得到一个 JSON 对象,它有 class 字段,但没有方法。您可以使用实例化 class 并使用 Object.assign
将对象文字中的值分配给每个 Point
实例
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()
将解决您当前的问题,但如果您有嵌套对象则不会。然后您还必须为每个嵌套对象执行 Object.assign()
,如果您必须在代码库的多个位置执行此操作,这会变得乏味。
我建议一个替代方案:class-transformer 有了这个,您可以使用注释标记嵌套字段,告诉编译器如何创建嵌套对象。有了这个,您只需要使用 plainToClass()
方法来映射您的顶级对象,所有基础字段也将具有正确的 types/objects.
例子
假设我们有两个 classes:
class Parent {
name: string;
child: Child;
public getText(): string {
return 'parent text';
}
}
class Child{
name: string;
public getText(): string {
return 'child text';
}
}
我们已经知道的第一种情况不起作用:
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
第二种情况 使用Object.assign()
:
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!
要使其正常工作,我们必须执行以下操作:
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
第三种情况与class-transformer:
首先修改父class以便定义子映射:
class Parent {
name: string;
@Type(() => Child)
child: Child;
public getText(): string {
return 'parent text';
}
}
然后你可以映射到父对象:
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
我在 typescript/angular.
中遇到对象和类型的一些奇怪的(对我来说)问题我有一些 class 描述了我从远程接收的对象 API:
export class Point {
lat:number;
lng:number;
name:string;
public doSomething() {
console.log("doSomething called");
}
}
我正在使用 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
}
);
}
我的问题是,当我尝试在数组
中的一个点上调用方法doSomething
时
var firstPoint = points[0];
firstPoint.doSomething()
我在控制台上收到一些奇怪的错误:
ERROR TypeError: firstPoint.doSomething is not a function
我很长时间没有使用 Typescript 和 Angular,所以我假设我的代码有问题,但我找不到问题的答案。你能给我一些建议吗?
问题是您实际上并没有从 Web 服务中获取 Point
的实例。你得到一个 JSON 对象,它有 class 字段,但没有方法。您可以使用实例化 class 并使用 Object.assign
将对象文字中的值分配给每个 Point
实例
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()
将解决您当前的问题,但如果您有嵌套对象则不会。然后您还必须为每个嵌套对象执行 Object.assign()
,如果您必须在代码库的多个位置执行此操作,这会变得乏味。
我建议一个替代方案:class-transformer 有了这个,您可以使用注释标记嵌套字段,告诉编译器如何创建嵌套对象。有了这个,您只需要使用 plainToClass()
方法来映射您的顶级对象,所有基础字段也将具有正确的 types/objects.
例子
假设我们有两个 classes:
class Parent {
name: string;
child: Child;
public getText(): string {
return 'parent text';
}
}
class Child{
name: string;
public getText(): string {
return 'child text';
}
}
我们已经知道的第一种情况不起作用:
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
第二种情况 使用Object.assign()
:
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!
要使其正常工作,我们必须执行以下操作:
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
第三种情况与class-transformer:
首先修改父class以便定义子映射:
class Parent {
name: string;
@Type(() => Child)
child: Child;
public getText(): string {
return 'parent text';
}
}
然后你可以映射到父对象:
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