使用Angular& TypeScript,我们可以使用泛型和所有Compile-goodness来确保某种类型的安全性。但是,如果我们使用例如HTTP服务,我们不会获得特定的目标,只是解析了JSON。例如,我们有一些通用的方法:
public get<T>(relativeUrl: string): Promise<T> {
const completeUrlPromise = this.createCompleteUrl(relativeUrl);
const requestOptions = this.createRequestOptions(ContentType.ApplicationJson, true);
return completeUrlPromise.then(completeUrl => {
return this.processResponse<T>(this.http.get(completeUrl, requestOptions));
});
}
private processResponse<T>(response: Observable<Response>): Promise<T> {
const mappedResult = response.map(this.extractData);
const result = mappedResult.toPromise();
return result;
}
private extractData(res: Response): any {
let body;
if (!Array.isArray(res)) {
if (res.text()) {
body = res.json();
}
} else {
body = res;
}
if (!JsObjUtilities.isNullOrUndefined(body)) {
return body;
}
return {};
}
最终,泛型类型以这种方式无用,因为我们只获得了JSON。如果通用对象具有不在JSON中的方法或属性,则它们将丢失。 为了避免这种情况,我们增加了传递构造函数来真正创建对象的可能性:
private processResponse<T>(response: Observable<Response>, ctor: IParameterlessConstructor<T> | null = null): Promise<T> {
let mappedResult = response.map(this.extractData);
if (ctor) {
mappedResult = mappedResult.map(f => {
const newObj = JsObjFactory.create(f, ctor);
return newObj;
});
}
const result = mappedResult.toPromise();
return result;
}
JsObjFactory看起来像这样:
export class JsObjFactory {
public static create<T>(source: any, ctorFn: IParameterlessConstructor<T>): T {
const result = new ctorFn();
this.mapDefinedProperties(source, result);
return result;
}
private static mapDefinedProperties<T>(source: Object, target: T): void {
const properties = Object.getOwnPropertyNames(target);
properties.forEach(propKey => {
if (source.hasOwnProperty(propKey)) {
target[propKey] = source[propKey];
}
});
}
}
这适用于浅层对象,但如果属性也是带构造函数的复杂类型,则不起作用。由于在运行时没有类型,我目前最好的办法是善意解析属性,检查类是否存在然后创建它们。但这似乎非常容易出错并且很麻烦。
由于我始终确定,我不是唯一有这个问题的人,是否有解决方案,或者我不知道的TypeScript / JavaScript功能,这会有帮助?
答案 0 :(得分:0)
我个人不是这样做的,但它可能是你正在寻找的。 p>
示例:
<强> Customer.ts 强>
export interface ICustomer {
Id: number;
Name: string;
Orders: IOrder[];
...
}
export class Customer implements ICustomer {
public Id: number;
public Name: string;
public Orders: IOrder[];
constructor(customer: Partial<ICustomer>) {
this.Id = customer.Id || 0;
this.Name = customer.Name || '';
this.Orders = [];
customer.Orders.forEach((order: IOrder) => this.Orders.push(new Order(order)));
}
//some functions
}
<强> Order.ts 强>
export interface IOrder {
Id: number;
Weight: number;
Shipmentdate: string;
}
export class Order implements IOrder {
public Id: number;
public Weight: number;
public Shipmentdate: string;
constructor(order: Partial<IOrder>) {
this.Id = order.Id || 0;
this.Weight = order.Weight || 0;
this.Shipmentdate = order.Shipmentdate || '';
}
//some functions
}
这会使Object
(在这种情况下为Customer
)负责实例化您传入的已知复杂类型。Order
反过来又可能有其复杂性它实例化的类型。