gpt4 book ai didi

javascript - 如何在 Typescript 中进行类型安全的 Web 服务调用

转载 作者:行者123 更新时间:2023-12-03 02:02:36 26 4
gpt4 key购买 nike

使用 Angular 进行 Web 服务调用时,不会验证返回对象的类型。这可能意味着我有一个 Typescript 类:

export class Course {
constructor(
public id: number,
public name: string,
public description: string,
public startDate: Date
) {}
}

和 DataService 类:

import { Injectable } from '@angular/core';
import { Headers, Http, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class DataService {
constructor(private http: Http) { }

public get<T>(url: string): Observable<T> {
const headers = new Headers();
headers.append('content-type', 'application/json');
const options = new RequestOptions({ headers: headers, withCredentials:
true });
return this.http.get(url, options)
.map(response => response.json() as T);
}
}

然后执行:

import { Component } from '@angular/core';
import { DataService } from './data.service';
import { Course } from './course';


@Component({
selector: 'app-course',
templateUrl: './course.component.html',
styleUrls: ['./course.component.css']
})
export class CourseComponent {
private courseId: number;

constructor(private dataService: DataService) { }

public getData() {
this.dataService.get<Course>(`http://myapi/course/${this.courseId}`)
.subscribe(
course => this.course = course;
);
}
}

并且我不会遇到编译错误,因为我的数据服务正确地返回了“类(class)”类型的对象。

如果我的 API 实际上返回了以下 JSON:

{
"uniqueId": 123,
"name": "CS 101",
"summary": "An introduction to Computer Science",
"beginDate": "2018-04-20"
}

如果我尝试对不存在的属性(id、summary、startDate)执行某些操作,我不会收到编译时错误,并且只会收到运行时错误。这消除了 TypeScript 的一些类型安全性。

最佳答案

解决方案

我们可以通过修改我们的数据服务来解决此问题,如下所示:

import { Injectable } from '@angular/core';
import { Headers, Http, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';


@Injectable()
export class DataService {
constructor(private http: Http) { }

private verifyObjectWithTemplate(template: any, obj: any, graph: string[]) {
if (!template) {
return;
}

const graphString = graph.join('.');

Object
.getOwnPropertyNames(template)
.forEach(property => {
if (!obj.hasOwnProperty(property)) {
console.error(`Object is missing property: ${graphString}.${property}`);
} else {
const newGraph = graph.map(i => i);
newGraph.push(property);
this.verifyObjectWithTemplate(template[property], obj[property], newGraph);
}
});
}

public get<T>(url: string, template: T): Observable<T> {
const headers = new Headers();
headers.append('content-type', 'application/json');
const options = new RequestOptions({ headers: headers, withCredentials: true });
return this.http.get(url, options)
.map(response => {
const obj = response.json() as T;
this.verifyObjectWithTemplate(template, obj, []);
return obj;
});
}
}

向我们的 Course 类添加一个"template":

export class Course {
public static readonly Template = new Course(-1, '', '', new Date());
constructor(
public id: number,
public name: string,
public description: string,
public startDate: Date
) {}
}

并修改我们的类(class)组件以将模板传递给数据服务:

import { Component } from '@angular/core';
import { DataService } from './data.service';
import { Course } from './course';

@Component({
selector: 'app-course',
templateUrl: './course.component.html',
styleUrls: ['./course.component.css']
})
export class CourseComponent {
private courseId: number;

constructor(private dataService: DataService) { }

public getData() {
this.dataService.get<Course>(`http://myapi/course/${this.courseId}`, Course.Template)
.subscribe(
course => this.course = course;
);
}
}

然后,数据服务将验证 API 返回的 JSON 是否具有成为有效类(class)对象所需的所有属性。

数组呢?如果我们的一个类包含一个数组,例如我们的 Student 类,该怎么办:

import { Course } from './course';

export class Student {
public static readonly Template = new Student(-1, '', [Course.Template]);
constructor(
public id: number,
public name: string,
public courses: Course[]
) {}
}

在这种情况下,我们需要确保模板中的任何数组都包含一项,因此也可以验证这一点。我们还需要更新我们的数据服务,如下所示:

import { Injectable } from '@angular/core';
import { Headers, Http, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';


@Injectable()
export class DataService {
constructor(private http: Http) { }

private verifyObjectWithTemplate(template: any, obj: any, graph: string[]) {
if (!template) {
return;
}

const graphString = graph.join('.');

// Important that we compare object to undefined, and not to null.
// Property being null can be valid.
if (obj === undefined) {
console.error(`Object is missing property: ${graphString}`);
return;
}

if (obj === null) {
// No need to check rest of graph if object is null.
return;
}

if (Array.isArray(template)) {
if (!template[0]) {
console.error(`Template array is empty: ${graphString}`);
return;
}

if (!Array.isArray(obj)) {
console.error(`Object is not an array: ${graphString}`);
return;
}

if (!obj[0]) {
console.log(`Object array is empty so can't be verified: ${graphString}`);
return;
}

template = template[0];
obj = obj[0];
}

Object
.getOwnPropertyNames(template)
.forEach(property => {
if (!obj.hasOwnProperty(property)) {
console.error(`Object is missing property: ${graphString}.${property}`);
} else {
const newGraph = graph.map(i => i);
newGraph.push(property);
this.verifyObjectWithTemplate(template[property], obj[property], newGraph);
}
});
}

public get<T>(url: string, template: T): Observable<T> {
const headers = new Headers();
headers.append('content-type', 'application/json');
const options = new RequestOptions({ headers: headers, withCredentials:
true });
return this.http.get(url, options)
.map(response => {
const obj = response.json() as T;
this.verifyObjectWithTemplate(template, obj, []);
return obj;
});
}
}

现在应该能够处理所有类型的对象。

示例如果 Web 服务返回 JSON:

{
"uniqueId": 1,
"name": "Daniel",
"courses": [
{
"uniqueId": 123,
"name": "CS 101",
"summary": "An introduction to Computer Science",
"beginDate": "2018-04-20"
}
]
}

然后我们会在控制台中看到以下消息: errors

关于javascript - 如何在 Typescript 中进行类型安全的 Web 服务调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49946917/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com