2015-05-13 13 views
13

Chciałbym utworzyć ogólną klasę TypeScript do renderowania (jako listy HTML) tablicy obiektów, które implementują określony interfejs TypeScript.W maszynopisie: Czy istnieje sposób "kompilacji", aby uzyskać wszystkie nazwy właściwości zdefiniowane w interfejsie TypeScript?

np.

class GenericListRenderer<T> { 
    items: T[]; 

constructor(listItems: T[], className?: string){ 
     this.items = listItems; 
     ... 
    } 

    private getPropertyNames(): string[]{ 

    // What is the best way to access all property names defined in 
    // TypeScript interface 'T' that was used in this generic? 
    ... 
    } 

    render(){ 
     var propNames: string[] = this.getPropertyNames(); 
     // render list with each item containing set of all 
     // key(prop name)/value pairs defined by interface 'T' 
     ... 

    } 
} 

Pytanie: jaki byłby najlepszy sposób uzyskania listy "kompilacji" wszystkich nazw właściwości zdefiniowanych w określonym() interfejsie TypeScript?

Podobnie jak szablony C++, uważam, że TypeScript może rozróżniać te generyczne podczas "czasu kompilacji", kiedy informacja typu TypeScript (jak interfejs dostarczony do generycznego używanego do tworzenia instancji danego obiektu) jest łatwo dostępna.

Ponieważ wszystkie wymagane informacje o typie są potencjalnie dostarczane, byłem po prostu ciekawy, czy dostępne jest rozszerzenie/obiekt TypeScript, aby uzyskać dostęp do tych informacji bez nadmiernego filtrowania plików JavaScript o "wanilii" - co może być problematyczne z powodu do niejednoznacznych problemów związanych z dziedziczeniem (np. pożądane właściwości dziedziczone przez TypeScript mogą zostać odfiltrowane, jeśli do właściwości filtrowania używany jest język wykonawczy, ogólny, JavaScript (obj.hasOwnProperty (prop)).

Ten przydatny potencjał introspekcji może być jednoznacznie rozwiązany przy pomocy super-zestawu typowych danych metadanych podczas "kompilacji", a próba rozwiązania tych informacji w przetłumaczonym kodzie JavaScript, gdy wszystkie informacje tego typu zostaną odrzucone.

Nie chciałbym "wymyślać na nowo" kółka z potencjalnie niedoskonałym hackem JavaScript, jeśli istnieje standardowe podejście (TypeScript).

poważaniem: Początkujący maszynopis Guy, John

+0

W środowisku wykonawczym jest to zwykły kod JavaScript, więc w rzeczywistości poszukujesz metody JavaScript, aby uzyskać wszystkie właściwości ... i na to odpowiada http://stackoverflow.com/questions/85992/how-do-i -inumerate-the-properties-of-a-javascript-object – Markus

Odpowiedz

0

Nie możesz. W tym czasie nie jest to już TypeScript, to zwykły JavaScript bez interfejsów lub silne pisanie.

Nie można odwoływać się do konstrukcji TypeScript w środowisku wykonawczym.

+0

Mówi o czasie kompilacji, na przykład jak w C++ (https://www.gnu.org/software/gcc/projects/cxx-reflection/) – titusfx

+0

@titusfx Zdaję sobie sprawę, ale nie jest to możliwe bez typów dostępnych dla środowiska wykonawczego. –

+0

nie chodzi o czas wykonywania kompilacji, który interfejs jest dostępny. I lepiej, jest api https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API, można również zrobić transformatory https://github.com/Microsoft/TypeScript/issues/14419. Takie podejście jest odpowiedzią. Co jest trudne w tej chwili. – titusfx

0

W czasie wykonywania wszystkie informacje o typach są usuwane, więc najlepiej jest wyliczyć właściwości jednego z obiektów. Spowoduje to przywrócenie wszystkich właściwości, nawet tych, które nie znajdowały się w określonym interfejsie.

class GenericListRenderer<T> { 

    constructor(private items: T[], private className?: string){ 

    } 

    private getPropertyNames(): string[] { 
     var properties: string[] = []; 

     if (this.items.length > 0) { 
      for (var propertyName in this.items[0]) { 
       console.log(propertyName); 
       properties.push(propertyName); 
      } 
     } 

     return properties; 
    } 

    render(){ 
     var propNames: string[] = this.getPropertyNames(); 
    } 

} 

class Example { 
    constructor(public name: string) { 

    } 
} 

var example = new Example('Steve'); 

var a = new GenericListRenderer<Example>([example]); 

a.render(); 

Istnieje również Object.keys(), który daje z powrotem wszystkie właściwości, chociaż jest obsługiwana tylko w IE9 i powyżej.

Jeśli możesz podać więcej przypadków użycia dla tego, co chcesz zrobić z właściwościami, może być możliwe podanie alternatywnego rozwiązania przy użyciu atrybutów lub innego mechanizmu.

+0

To jest pocieranie: wygląda na to, że rozwiązanie środowiska wykonawczego nie wykorzystałoby odrzuconych meta-danych pisma, co prowadzi mnie do przekonania, że ​​tylko "kompilacyjne" rozwiązanie TypeScript mogłoby załatwić sprawę. Ponieważ nie jestem guru TypeScript: tylko zastanawiam się, czy taka użyteczna zdolność już istniała. – user3413621

4

Nie można odzyskać tych informacji w czasie wykonywania i nigdy nie będą one domyślne, chyba że zostaną zapisane podczas kompilacji. Rozwiązanie jest zatem w odbiciu przy użyciu ReflectDecorators.

Here to doskonały artykuł poświęcony zagadnieniu pobierania metadanych czasu kompilacji w środowisku wykonawczym. W skrócie: dodajesz do interfejsu dekoratora, który chcesz zachować, a ten zostanie przekonwertowany na obiekt json, który zostanie zapisany w samym kodzie. W czasie wykonywania będzie można pobrać ten obiekt Json zawierający wszystkie dane interfejsu. To jest teraz eksperymentalne (11 lutego 2016), ale w dobry sposób.

Uwaga: Powodem, dla którego nigdy nie będzie według domyślnej konfiguracji, jest w zasadzie wybór projektu, aby nie przeciążyć kodu js za pomocą metadanych (w przeciwieństwie do Dart).

+2

_ "chyba że przechowujesz je podczas kompilacji" _: jako luźna implementacja, stworzyłem 'static PROP_NAMES: string [] = ['prop1', 'prop2', 'propN'];' in 'MyClass'. Następnie robię 'MyClass.PROP_NAMES.forEach (key => {/ * zrobić coś * /});' –

7

Jest to możliwe dzięki zastosowaniu niestandardowych transformatorów wprowadzonych przez https://github.com/Microsoft/TypeScript/pull/13940, które są dostępne w maszynopisie @ dalej.

Mój pakiet npm, ts-transformer-keys, jest dobrym przykładem.

import { keys } from 'ts-transformer-keys'; 

interface Props { 
    id: string; 
    name: string; 
    age: number; 
} 
const keysOfProps = keys<Props>(); 

console.log(keysOfProps); // ['id', 'name', 'age'] 
+0

To wygląda dobrze, ale wydaje się wymagać specjalnej procedury kompilacji - czy to prawda? Byłoby też świetnie, gdyby istniała funkcja "optionalKeys" - która zwróciła opcje. Umożliwiłoby to sprawdzenie wymaganego czasu pracy rekwizytów w sposób bezpieczny dla określonych typów. –

+0

Dobrze. Występuje problem z obsługą wtyczek dla niestandardowych transformatorów: https://github.com/Microsoft/TypeScript/issues/14419. Nie jest trudno zaimplementować funkcję "optionalKeys" z niestandardowymi transformatorami. – kimamula