2015-08-23 16 views
14

Şu anda bir typescript projesi üzerinde çalışıyorum ve TypeScript'in tabloya getirdiği tür çıkarımından gerçekten keyif alıyorum. Ancak - HTTP nesneleri alırken çağrıları - Zamanım derlemek , istenen türüne onları döküm kod tamamlama almak ve üzerlerinde işlevleri çağırmak, ancak hatalar bu sonucu çalışma zamanıTypeScript'te çalışma zamanı türü dökümleme nasıl yapılır?

Örnek:

class Person{ 
    name: string; 

    public giveName() { 
     return this.name; 
    } 

    constructor(json: any) { 
     this.name = json.name; 
    } 
} 

var somejson = { 'name' : 'John' }; // Typically from AJAX call 
var john = <Person>(somejson);  // The cast 

console.log(john.name);  // 'John' 
console.log(john.giveName()); // 'undefined is not a function' 

Bu, güzel bir şekilde derlenmiş olsa da ve intellisense işlevi kullanmamı önerse de, bir çalışma zamanı istisnası verir. Bunun için bir çözüm:

var somejson = { 'name' : 'Ann' }; 
var ann = new Person(somejson); 

console.log(ann.name);  // 'Ann' 
console.log(ann.giveName()); // 'Ann' 

Ancak bu, tüm türlerim için kurucular oluşturmamı gerektirecektir. Patikularda, ağaç benzeri tiplerle ve/veya AJAX-çağrısı ile gelen koleksiyonlarla uğraşırken, tüm öğeler arasında dolaşmak ve her biri için yeni bir örnek oluşturmak gerekir.

Benim soru: Bunu yapmak için daha şık bir yolu var mı? Yani, bir türe dökülür ve prototipik işlevler anında kullanılabilir mi?

+0

Tip döküm, derleyici/IDE için sadece bir ipucudur. Düz Javascript nesnesine asla yöntem eklemez. Yani JSON verilerini bir 'Kişi' nesnesi olarak örneklemelisiniz, bunun için bir yol yok. Nesneleri/dizileri sizin için anında oluşturmak için bir yardımcı fonksiyon yazabilirsiniz. Ve bu notta, döküm size bir dizi nesne ile nasıl yardımcı olur? Hala dizinin üzerinde yinelemek ve her bir öğeyi yayınlamak zorundasınız, değil mi? –

cevap

5

Derlenmiş Javascript'e bir göz atın ve siz sadece derleme için olduğu için türün kaybolduğunu göreceksiniz. Şu anda derleyiciye somejson nesnesinin Person türünde olduğunu söylüyorsunuz. Derleyici size inanıyor, ancak bu durumda bu doğru değil.

Bu sorun, bir çalışma zamanı JavaScript sorundur.

Bunu işe koymanın temel amacı, bir şekilde JavaScript'in sınıflar arasındaki ilişkinin ne olduğunu anlatmasıdır. Yani ...

  1. sınıflar arasındaki ilişkiyi açıklamak için bir yol bulun.
  2. Bu ilişki verilerine göre jsonları otomatik olarak sınıflara eşlemek için bir şeyler oluşturun.

bunu çözmek için birçok yolu vardır, ama başımın üstü kapalı bir örnek sunacağız. Bu, yapılması gerekenleri açıklamaya yardımcı olmalıdır. Biz benzer türdeki nasıl JavaScript söylememe gerek

{ 
    name: 'John', 
    child: { 
     name: 'Sarah', 
     child: { 
      name: 'Jacob' 
     } 
    } 
} 

Person örnekleri olmak otomatik olarak bu eşleştirmek için:

class Person { 
    name: string; 
    child: Person; 

    public giveName() { 
     return this.name; 
    } 
} 

Ve bu json verilerini:

bu sınıf var ki . TypeScript türü bilgilerini kullanamıyoruz çünkü bir kere derlendikten sonra kaybedeceğiz. Bunu yapmanın bir yolu, bunu açıklayan türde bir statik özelliğe sahip olmaktır.Örneğin: Aşağıdaki kod çalışacaktır Şimdi

function createInstanceFromJson<T>(objType: { new(): T; }, json: any) { 
    const newObj = new objType(); 
    const relationships = objType["relationships"] || {}; 

    for (const prop in json) { 
     if (json.hasOwnProperty(prop)) { 
      if (newObj[prop] == null) { 
       if (relationships[prop] == null) { 
        newObj[prop] = json[prop]; 
       } 
       else { 
        newObj[prop] = createInstanceFromJson(relationships[prop], json[prop]); 
       } 
      } 
      else { 
       console.warn(`Property ${prop} not set because it already existed on the object.`); 
      } 
     } 
    } 

    return newObj; 
} 

:

const someJson = { 
     name: 'John', 
     child: { 
      name: 'Sarah', 
      child: { 
       name: 'Jacob' 
      } 
     } 
    }; 
const person = createInstanceFromJson(Person, someJson); 

console.log(person.giveName());    // John 
console.log(person.child.giveName());  // Sarah 
console.log(person.child.child.giveName()); // Jacob 

class Person { 
    static relationships = { 
     child: Person 
    }; 

    name: string; 
    child: Person; 

    public giveName() { 
     return this.name; 
    } 
} 

Sonra burada bu ilişki verilerine dayanarak bizim için nesneleri oluştururken kolları yeniden kullanılabilir fonksiyonun bir örnek

Playground

İdeal, en iyi yol, aslında TypeScript kodunu okuyan ve sınıflar arasındaki ilişkiyi tutan bir nesne oluşturan bir şeyin kullanılması olacaktır. Bu şekilde, ilişkileri el ile sürdürmemize ve kod değişiklikleri konusunda endişelenmemize gerek yoktur. Örneğin, şu anda kodu yeniden düzenleme kodu bu kurulumla ilgili bir risktir. Şu an böyle bir şeyin var olduğundan emin değilim, ama kesinlikle mümkün.

Alternatif Çözüm Sadece ben zaten biraz farklı çözüm ile benzer bir soru cevap fark

(yani gerçi yuvalanmış verileri içermez). Biraz daha fazla fikir için buradan okuyabilirsiniz:

JSON to TypeScript class instance?

+0

İşlev tanımındaki jeneriği zaten belirttiğinizden beri 'objType' argümanını kullanarak atlamak için bir yol olmalı gibi görünüyor ... belki de, bir yolun olup olmadığını görmek için şimdiki tipo jeneriklerini okuyorum. Sadece json' argümanında geçmek zorunda ... –

+0

@DannyBullis bununla ilgili tek sorun, JavaScript derlediğinden, tür bilgisi (dahil olan jenerikler) çalışma zamanında kaybolur. Kod yazısının kendisi analiz edilerek ve sonra da bundan kod üretilerek çözülebilir. Bu daha karmaşık bir çözüm. Bunu nasıl yapacağımı biliyorum, ama sadece yazmak için etrafta dolaşmak zorundayım (muhtemelen bunu yapacağım tatilde ... bir hatırlatma oluşturdum). –

+0

ahh Bunu fark ettim. Devam edeceğim. İyi şanslar ve mutlu tatiller. –

7

sınıfın prototip dinamik nesnesine etkilenebilir:

function cast<T>(obj: any, cl: { new(...args): T }): T { 
    obj.__proto__ = cl.prototype; 
    return obj; 
} 

var john = cast(/* somejson */, Person); 

the documentation of __proto__ here bakınız.

+1

J'aime lire la documentation en francais;) Bu çözüm, sınıfın herhangi bir ok işlevi olmadığı sürece çalışır. –

+0

Ha ha! Afedersiniz! Düzenledim. Özellikler (ok işlevleri dahil), prototipte değil, nesne örneğinde saklanır. Evet, bu çözüm nesnede herhangi bir özellik eklemeyecek. – Paleo

İlgili konular