Kuinka voin laskea, mitkä ominaisuudet ovat käytössä TypeScript-objektityypissä?


Etsin tapaa laskea, mitkä osat objektityypeistäni ovat todella käytössä koko koodipohjassani. Oletetaan, että minulla on seuraava types.ts-tiedostossa:

export type Animal = {
  id: number;
  name: string;
  height: number;
  isMammal: boolean;
}

Ja toisessa tiedostossa teen API-kutsun, joka palauttaa Eläimen:

const getAnimal: (id: number) => Promise<Animal>

Ja kahdessa erillisessä tiedostossa kutsun getAnimal ja käytän tuloksena olevaa Animal-oliota.

const animal1 = await getAnimal(1);
console.log(`Hi! Animal with id ${animal1.id} is named ${animal1.name}.`)
const animal1 = await getAnimal(1);
console.log(`This animal is ${animal1.height} feet tall.`)

Mutta missään projektissani en käytä isMammal-ominaisuutta. Kuinka voisin kirjoittaa skriptin, joka käy läpi kaikki projektini tiedostot ja kertoo minulle, että isMammal ei ole käytössä Animal-tyypissä? Tai vaihtoehtoisesti, että vain id, name ja height ovat?

Vastaus #1

Tätä varten kääntäjän API:n kanssa haluat käyttää ja asettaa ts.LanguageServer käyttämällä ts.createLanguageService(...), ja sitten käyttää findReferences-metodia, joka palauttaa kaikki viittaukset, joita käytetään samalla tavalla kuin editorissa.

Tässä on itsenäinen esimerkki:

// setup code because doing this with the compiler API alone is a lot to show
import { createProjectSync, ts } from "https://deno.land/x/[email /bootstrap/mod.ts";

const project = createProjectSync();
const sourceFile = project.createSourceFile("file.ts", `
export type Animal = {
  id: number;
  name: string;
  height: number;
  isMammal: boolean;
};

const animal: Animal = {} as any;
animal.id;
animal.name;
animal.height;
`);
const languageService = project.getLanguageService();

// compiler API code starts here
const animalType = sourceFile.statements[0] as ts.TypeAliasDeclaration;
const animalObjectType = animalType.type as ts.TypeLiteralNode;

for (const member of animalObjectType.members) {
  if (ts.isPropertySignature(member)) {
    const findResult = languageService.findReferences(
      sourceFile.fileName,
      member.name.getStart(sourceFile),
    );
    const references = (findResult ?? [])
      .reduce<ts.ReferencedSymbolEntry[]>((a, b) => a.concat(b.references), [])
      .filter(r => !r.isDefinition);
    if (references.length === 0) {
      console.log(member.name.getText(sourceFile));
    }
  }
}

Tulosteet :

isMammal

Vastaus #2

Päivitys: Katso @David Sherretin vastaus. Se on parempi kuin minun :)

@T.J. Crowder ehdotti TypeScript-kääntäjärajapinnan tutkimista. En myöskään ole tutkinut sitä syvällisesti, mutta nopealla vilkaisulla se ei vaikuta kovin liittyvältä siihen, mitä haluat tehdä. Se on rajapinta TypeScriptin kääntäjälle.

Ehdottaisin myös tutustumaan Language Service API:in (se mikä on pohjana monelle TypeScriptin IDE-integraatiolle IDE:issä kuten VS Code), joka luultavasti on lähempänä sitä mitä haluat. On olemassa suoritettava tiedosto "tsserver", joka käärii compiler API:n ja kielipalvelun, mikä saattaa mahdollisesti olla käyttäjäystävällisempi sinulle. Katso lisätietoja käytöstä liitetyltä wiki-sivulta.

Erityisesti, jos katsot viitattua protokollan .d.ts-tiedostoa, näet

    /**
     * Instances of this interface specify a location in a source file:
     * (file, line, character offset), where line and character offset are 1-based.
     */
    interface FileLocationRequestArgs extends FileRequestArgs {
        /**
         * The line number for the request (1-based).
         */
        line: number;
        /**
         * The character offset (on the line) for the request (1-based).
         */
        offset: number;
    }

// ...

    /**
     * A request whose arguments specify a file location (file, line, col).
     */
    interface FileLocationRequest extends FileRequest {
        arguments: FileLocationRequestArgs;
    }

// ...

    /**
     * Find references request; value of command field is
     * "references". Return response giving the file locations that
     * reference the symbol found in file at location line, col.
     */
    interface ReferencesRequest extends FileLocationRequest {
        command: CommandTypes.References;
    }

Voit painaa ctrl+F "ReferencesResponse" löytääksesi osien vastausdatan rajapintamääritelmät.

Jos haluat kokeilla tätä, seuraavat vaiheet olisivat luoda ohjelma, joka ottaa argumentteja, jotka määrittävät tiedostojen sijainnit tyyppimäärittelyille, joita haluat skannata viitteiden varalta, ja sitten perustaa paikallisen tsserverin ja tehdä siihen kutsuja löytääksesi viitteitä näiden tyyppimäärittelyjen kenttiin, ja koota lista kentistä, joita ei viitata missään projektissa.

Tämä on hyvin kaukana täydellisestä vastauksesta, mutta rehellisyyden nimissä en usko, että tämä on kovin usein tutkittu alue (siitä huolimatta, että käyttämättömien muuttujien ja parametrien löytäminen on ratkaistu ongelma), ja jos se todella on niin, en usko, että odotit kenenkään tulevan tekemään kaiken työsi puolestasi (tai ehkä odotit. En ole kovin perehtynyt Stack Overflow -kulttuuriin).

Aiheeseen liittyviä artikkeleita