typescript - Inferă valori din obiect


Cum pot să deduc toate valorile dintr-un obiect ca acesta…

const fruits = {
  a: 'apple',
  b: 'banana'
};

…așa că să primesc asta?

type fruitValues = 'apple' | 'banana';

(Cred că caut echivalentul lui $Values<T> în Flow)

Răspuns #1

Poți deduce tipul din obiect, dar obiectul a fost deja dedus că deține doar proprietăți string. Adică, tipurile "apple" și "banana" au fost lărgite la string, așa cum se menționează în problema relevantă de pe GitHub, pentru că sunt proprietăți ne-readonly.

const fruits = {
  a: 'apple',
  b: 'banana'
};

type FruitValues = (typeof fruits)[keyof typeof fruits]; // string

Deci, FruitValues de mai sus nu este ceea ce vrei. Dacă vrei să te apropii mai mult, trebuie să previi această extindere. Un mod este să folosești afirmații de tip redundante, dar autonome:

const fruits = {
  a: 'apple' as 'apple',
  b: 'banana' as 'banana'
};

type FruitValues = (typeof fruits)[keyof typeof fruits]; // "apple" | "banana"

O altă modalitate este să creezi o funcție ajutătoare care inferă tipuri mai înguste:

// put in a library somewhere
type Narrowable = string | number | boolean | undefined | null | void | {};
const narrowObj = <V extends Narrowable, T extends { [k: string]: V }>(t: T) => t;

const fruits = narrowObj({
  a: 'apple',
  b: 'banana'
})

type FruitValues = (typeof fruits)[keyof typeof fruits]; // "apple" | "banana"

În cele din urmă, odată ce va fi lansat TypeScript 3.4 vor exista contexte const care vor deduce cel mai restrâns tip posibil (inclusiv transformarea tuturor proprietăților în readonly, ceea ce s-ar putea să nu doriți), astfel:

const fruits = {
  a: 'apple',
  b: 'banana'
} as const; // requires TS3.4+

type FruitValues = (typeof fruits)[keyof typeof fruits]; // "apple" | "banana"

Bine, sper că asta ajută. Mult noroc!