typescript - Bevara nyckeltyp vid användning av Object.entries()


Här är ett exempel på mitt problem (demo i ts-lekplatsen)

type Tkey = 'foo' | 'bar' | 'defaultKey'

const typedObject: Record<Tkey, Boolean> = {
  'foo': true,
  'bar': false,
  'defaultKey': true
}

// type does not persist string narrowing
const entries = Object.entries(typedObject) // [string, Boolean][]

Så key i [key, values] är av typen string och inte av typen Tkey.

Som en lösning kan du manuellt tvinga efteråt, men det skulle vara trevligt att definiera typen under operationen.

const typedEntries = entries as [Tkey, Boolean][]

Svar #1

Du kan utöka standard TypeScript-biblioteket genom att lägga till din egen objektdefinition som tar in två generiska typparameterar.

Lägg till följande i en globals.d.ts-fil i din projektrot:

interface ObjectConstructor {
    entries<TKey extends PropertyKey, TVal>(o: Record<TKey,TVal>): [TKey, TVal][];
    keys<TKey extends PropertyKey>(obj: Record<TKey,any>): TKey[];
}

Och sedan använd det så här:

const entries = Object.entries<ObjKeys, Boolean>(myObj) // [ObjKeys, Boolean][]
const keys = Object.keys<ObjKeys>(myObj) // ObjKeys[]

Demo i TS Playground

Svar #2

TypeScripts inbyggda definitionsfiler innehåller detta för Object.entries:

entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];

entries(o: {}): [string, any][];

Din enda chans att få det beteende du vill ha är att åsidosätta denna definition med något liknande detta:

interface YourOwnObject {
  entries<T>(o: { [K in keyof T]: T[K] }): [keyof T, T[keyof T]][];
}

(<YourOwnObject>Object).entries(typedObject).forEach(([key, values]) => {
  // ...
})

Relaterade artiklar