typescript - 'kompileringstid'-måte å få alle egenskapsnavn definert i grensesnitt


Jeg vil gjerne lage en generell TypeScript-klasse for å rendere (som en HTML-liste) et array av objekter som implementerer et spesifikt interface.

f.eks.

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'  
      ...

    }
}

Spørsmål: Hva ville være den beste måten å få en 'compile-time'-liste over alle egenskapsnavn som er definert i den angitte() TypeScript-grensesnittet?

Som C++-maler, tror jeg at TypeScript kan løse disse generiske typene under «kompileringstid», når TypeScript-typeinformasjon (som et grensesnitt gitt til den generiske typen som brukes til å instansiere et bestemt objekt) er lett tilgjengelig.

Siden all nødvendig typeinformasjon potensielt er tilgjengelig, var jeg bare nysgjerrig på om det finnes en TypeScript-utvidelse/fasilitet som gjør det mulig å få tilgang til denne informasjonen uten overdreven kjøretidsfiltrering av 'vanilla' JavaScript-objekter - noe som kan være problematisk på grunn av tvetydige arv-problemer (f.eks. ønskede TypeScript-arvede grensefladeegenskaper kan bli filtrert bort hvis kjøretids, generisk, JavaScript (obj.hasOwnProperty(prop)) brukes for å filtrere egenskaper).

Dette nyttige potensialet for egenskapsintrospeksjon kunne entydig løses med TypeScripts super-sett av typemetadata under 'kompileringstid' i stedet for å prøve å løse denne informasjonen i den oversatte Javascript, når all denne typeinformasjonen blir forkastet.

Jeg ville hatet å 'oppfinne hjulet på nytt' med en potensielt feilaktig Javascript-løsning hvis en standard (TypeScript) tilnærming finnes.

Svar #1

Dette er mulig ved å bruke tilpassede transformatorer introdusert av https://github.com/Microsoft/TypeScript/pull/13940, som er tilgjengelig i typescript >= 2.4.1.

Mitt npm-pakke, ts-transformer-keys, er et godt eksempel.

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

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

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

Svar #2

Det er ikke mulig å hente denne informasjonen under kjøring, og de vil aldri være tilgjengelige som standard med mindre du lagrer dem under kompileringen. Løsningen er derfor å bruke refleksjon med ReflectDecorators.

Her er en utmerket artikkel som dekker spørsmålet om å hente kompileringstidmetadata under kjøretid. Kort sagt: du legger til en dekoratør på grensesnittet du ønsker å beholde beskrivelsen for, denne vil bli konvertert til et JSON-objekt som vil bli lagret i selve koden. Under kjøretid vil du kunne hente dette JSON-objektet som har alle grensesnittdataene. Dette er nå eksperimentelt (11. februar 2016) men på en god måte.

Merk: Grunnen til at det aldri vil være som standard, er i utgangspunktet et designvalg for TS for å ikke overbelaste js-koden med metadata (i motsetning til Dart).

Relaterte artikler