typescript - Cum pot să scriu o funcție generică care folosește tipul unui membru al unui enum în locul enumului în sine?
Documentația TypeScript despre enumerări spune:
membrii enum devin de asemenea și tipuri!
Aș dori să am o funcție care să ia o valoare generică care este un membru al unui enum și să folosească tipul membrului specific al enum-ului.
Văd că pot folosi membrul enum ca tip:
enum Kind {
Apple,
Banana,
}
type Example1 = Kind.Apple;
Pot folosi membrul enum într-un context de tip generic:
interface Wrapper<K> {
kind: K;
}
type Example2 = Wrapper<Kind.Apple>;
Când trec membrul enum la o funcție, acesta își pierde faptul că este un membru specific al enum și în schimb devine tipul enum-ului părintelui:
const returned = <K>(kind: K): Wrapper<K> => ({
kind,
})
const theValue = returned(Kind.Apple);
// Type 'Kind' is not assignable to type 'Kind.Apple'.
const butNot: Example2 = theValue;
Teren de joacă
Răspuns #1
Motivul pentru care tipul parametrului kind este lărgit de la Kind.Apple la Kind este explicat în https://github.com/Microsoft/TypeScript/pull/10676 :
În timpul inferenței argumentului de tip pentru o expresie de apel, tipul inferat pentru un parametru de tip T este largit la tipul său literal extins dacă:
- toate inferențele pentru T au fost făcute pentru aparițiile de nivel superior ale lui T în cadrul tipului de parametru respectiv, și
- T nu are nicio constrângere sau constrângerea sa nu include tipuri primitive sau literale, și
- T a fost fixat în timpul inferenței sau T nu apare la nivel superior în tipul returnat.
Dacă, așa cum se menționează în al doilea punct, adăugați o constrângere pentru parametrul generic T, acesta va începe să deducă tipul literal specific. Prețul pentru asta este că face ca returned să fie aplicabil doar subtipurilor lui Kind.
enum Kind {
Apple,
Banana,
}
interface Wrapper<K> {
kind: K;
}
const returned = <K extends Kind>(kind: K): Wrapper<K> => ({
kind,
})
const theValue = returned(Kind.Apple);
const thisWorksNow: Wrapper<Kind.Apple> = theValue;
Răspunsul #2
Poți specifica în mod explicit ce ar trebui să fie tipul generic la apelul returned:
enum Kind {
Apple,
Banana,
}
interface Wrapper<K> {
kind: K;
}
const returned = <K>(kind: K): Wrapper<K> => ({
kind,
})
const theValue = returned<Kind.Apple>(Kind.Apple);
const thisWorksNow: Wrapper<Kind.Apple> = theValue;
