Typescript with Angular HttpClient ErrorType ...在调用类方法时不是函数

Posted

技术标签:

【中文标题】Typescript with Angular HttpClient ErrorType ...在调用类方法时不是函数【英文标题】:Typescript with Angular HttpClient ErrorType ... is not a function when calling class method 【发布时间】:2018-11-04 20:53:42 【问题描述】:

我在 typescript/angular 中遇到了一些奇怪的(对我来说)对象和类型的问题。

我有一些描述从远程 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,所以我假设我的代码有问题,但我找不到问题的答案。你能给我一些建议吗?

【问题讨论】:

【参考方案1】:

问题是您实际上并没有从 Web 服务中获得 Point 的实例。你得到一个 JSON 对象,它有类字段,但没有方法。您可以使用实例化类并使用 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?或者也许可以将它移到其他地方,例如HttpInterceptor? @user3626048 我不知道另一种方法,你需要以某种方式传递构造函数(类型参数是不够的,因为它会在运行时被删除)【参考方案2】:

Object.assign() 将解决您当前的问题,但如果您有嵌套对象则不会。然后,您还必须为每个嵌套对象执行 Object.assign(),如果您必须在代码库中的多个位置执行此操作,这可能会变得乏味。

我建议另一种选择:class-transformer 使用它,您可以使用注释标记嵌套字段,告诉编译器如何创建嵌套对象。有了这个,您只需要使用plainToClass() 方法来映射您的***对象,所有底层字段也将具有正确的类型/对象。

示例

假设我们有两个类:

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 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 with Angular HttpClient ErrorType ...在调用类方法时不是函数的主要内容,如果未能解决你的问题,请参考以下文章

Angular 5 GET data with Observable and HttpClient - 从 Web API 获取数据

TypeScript:返回一个承诺的结果

Building-Mobile-Apps-with-Ionic-2中文翻译工作

[Typescript] Improve Readability with TypeScript Numeric Separators when working with Large Numbers(

带有 TypeScript 的 Angular 2 [关闭]

没有 TypeScript 的 Angular 8 依赖注入?