TypeScriptissä, mitä "extends keyof" ja "in keyof" tarkoittavat?


TypeScriptissä joitakin tyyppejä määritellään käyttämällä extends keyof tai in keyof. Olen yrittänyt ymmärtää, mitä ne tarkoittavat, mutta toistaiseksi en ole onnistunut.

Se, mitä sain, on se, että pelkkä keyof palauttaa unioni-tyypin, joka sisältää kaikki nimet mahdollisina arvoina, jotka ovat olemassa ominaisuuksien nimiä tyypissä, jonka määrität keyof jälkeen.

type T = keyof string;

T on siksi yhtä kuin startsWith | endsWith | trim | substring | ....

Onko tämä oikein?

Nyt, jos yritän ajatella, mitä extends keyof ja in keyof tarkoittavat, vaistoni sanoo seuraavaa:

  • extends keyof on mikä tahansa tyyppi, joka johdetaan T:stä, eli sillä on kaikki nämä mahdolliset arvot, mutta ehkä enemmän.
  • in keyof on mikä tahansa tyyppi, joka ottaa arvoja tyyppistä T, mutta ei välttämättä kaikista niistä (se on mahdollista, mutta ehkä vähemmän).

Joten tästä näkökulmasta extends keyof kuvaisi >= -suhdetta, in keyof kuvaisi <= -suhdetta. Onko tämä oikein? Jos ei, mikä olisi oikein?

Vastaus #1

Mille tahansa tyypille T, keyof T on tunnettuja, julkisia ominaisuuksien nimiä sisältävä yhdiste T:stä.

Esimerkki :

interface Person {
  age: number;
  name: string;
}

type PersonKeys = keyof Person; // "age" | "name"

Oletuksesi, että keyof string tuottaa startsWith | endsWith | trim | ..., on siksi oikea. Voit oppia siitä lisää hakutyyppien julkaisumuistiinpanoista.

laajentaa keyof

extends, tässä tapauksessa, käytetään rajoittamaan geneerisen parametrin tyyppiä. Esimerkki:

<T, K extends keyof T>

K voi siksi olla vain T:n julkinen ominaisuuden nimi. Sillä ei ole mitään tekemistä tyypin laajentamisen tai perinnön kanssa, toisin kuin rajapintojen laajentamisessa.

Yksi extends keyof-käytön tapa voisi olla seuraava:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const person: Person = {
  age: 22,
  name: "Tobias",
};

// name is a property of person
// --> no error
const name = getProperty(person, "name");

// gender is not a property of person
// --> error
const gender = getProperty(person, "gender");

Index-tyypeistä kertovan dokumentaation lisäksi löysin tämän hyödyllisen artikkelin.

avainof

in käytetään, kun määritellään indeksin allekirjoitus, jonka haluamme tyypittää merkkijonon, numeron tai symbolin literaalien yhdisteellä. Yhdessä keyof-avainsanan kanssa voimme käyttää sitä niin sanotun mapped type -tyypin luomiseen, joka uudelleenmäärittelee alkuperäisen tyypin kaikki ominaisuudet.

Yksi in keyof-käytön tapa voisi olla seuraava:

type Optional<T> = { 
  [K in keyof T]?: T[K] 
};

const person: Optional<Person> = {
  name: "Tobias"
  // notice how I do not have to specify an age, 
  // since age's type is now mapped from 'number' to 'number?' 
  // and therefore becomes optional
};

Muun muassa dokumentaation lisäksi kartoitetuista tyypeistä, löysin jälleen kerran tämän hyödyllisen artikkelin.

Hauska fakta: Rakentamallamme Optional<T>-tyypillä on sama allekirjoitus kuin virallisella Partial<T>-aputyypillä!

Aiheeseen liittyviä artikkeleita