ज्यादातर सही, लेकिन बहुत कुशल जवाब नहीं के साथ एक पुराना सवाल। यह मेरा प्रस्ताव है:
एक बेस क्लास बनाएं जिसमें इनिट () मेथड और स्टैटिक कास्ट मेथड्स (सिंगल ऑब्जेक्ट और एरे के लिए) हों। स्थैतिक विधियाँ कहीं भी हो सकती हैं; बेस क्लास और इनिट के साथ संस्करण () बाद में आसान एक्सटेंशन की अनुमति देता है।
export class ContentItem {
// parameters: doc - plain JS object, proto - class we want to cast to (subclass of ContentItem)
static castAs<T extends ContentItem>(doc: T, proto: typeof ContentItem): T {
// if we already have the correct class skip the cast
if (doc instanceof proto) { return doc; }
// create a new object (create), and copy over all properties (assign)
const d: T = Object.create(proto.prototype);
Object.assign(d, doc);
// reason to extend the base class - we want to be able to call init() after cast
d.init();
return d;
}
// another method casts an array
static castAllAs<T extends ContentItem>(docs: T[], proto: typeof ContentItem): T[] {
return docs.map(d => ContentItem.castAs(d, proto));
}
init() { }
}
इसी तरह के मैकेनिक्स ( असाइन () के साथ ) का उल्लेख @ Adam111p पोस्ट में किया गया है। इसे करने के लिए बस एक और (अधिक पूर्ण) तरीका है। @ टिमोथी पेरेस असाइनमेंट () के लिए महत्वपूर्ण है , लेकिन यह पूरी तरह से यहाँ उपयुक्त है।
एक व्युत्पन्न (वास्तविक) वर्ग को लागू करें:
import { ContentItem } from './content-item';
export class SubjectArea extends ContentItem {
id: number;
title: string;
areas: SubjectArea[]; // contains embedded objects
depth: number;
// method will be unavailable unless we use cast
lead(): string {
return '. '.repeat(this.depth);
}
// in case we have embedded objects, call cast on them here
init() {
if (this.areas) {
this.areas = ContentItem.castAllAs(this.areas, SubjectArea);
}
}
}
अब हम सेवा से प्राप्त एक वस्तु को डाल सकते हैं:
const area = ContentItem.castAs<SubjectArea>(docFromREST, SubjectArea);
सबजेक्टआरे ऑब्जेक्ट्स के सभी पदानुक्रम में सही वर्ग होगा।
एक उपयोग मामला / उदाहरण; एक कोणीय सेवा (फिर से आधार वर्ग) बनाएं:
export abstract class BaseService<T extends ContentItem> {
BASE_URL = 'http://host:port/';
protected abstract http: Http;
abstract path: string;
abstract subClass: typeof ContentItem;
cast(source: T): T {
return ContentItem.castAs(source, this.subClass);
}
castAll(source: T[]): T[] {
return ContentItem.castAllAs(source, this.subClass);
}
constructor() { }
get(): Promise<T[]> {
const value = this.http.get(`${this.BASE_URL}${this.path}`)
.toPromise()
.then(response => {
const items: T[] = this.castAll(response.json());
return items;
});
return value;
}
}
उपयोग बहुत सरल हो जाता है; एक क्षेत्र सेवा बनाएँ:
@Injectable()
export class SubjectAreaService extends BaseService<SubjectArea> {
path = 'area';
subClass = SubjectArea;
constructor(protected http: Http) { super(); }
}
सेवा का तरीका () विधि एक सरणी का वादा लौटाएगी जो पहले से ही डाली गई विषय वस्तु के रूप में (संपूर्ण पदानुक्रम)
अब कहते हैं, हमारे पास एक और वर्ग है:
export class OtherItem extends ContentItem {...}
एक ऐसी सेवा बनाना जो डेटा को पुन: प्राप्त करता है और सही वर्ग के लिए डाली जाती है, यह उतना ही सरल है:
@Injectable()
export class OtherItemService extends BaseService<OtherItem> {
path = 'other';
subClass = OtherItem;
constructor(protected http: Http) { super(); }
}