The typing for Object.entries
provided by typescript has the return type [string, T][]
but I am searching for a generic type Entries<O>
to represent the return value of this function that keeps the relationship between the keys and the values.
Eg. when having an object type like
type Obj = { a: number, b: string, c: number }
I'm looking for a type Entries<O>
that results in one of the types below (or something similar) when provided with Obj
:
(["a", number] | ["b", string] | ["c", number])[] [["a", number], ["b", string], ["c", number]] (["a" | "c", number] | ["b", string])[]
That this isn't correct for all use cases of Object.entries (see here) is no problem for my specific case.
Tried and failed solution:
type Entries<O> = [keyof O, O[keyof O]][]
doesn't work for this as it only preserves the possible keys and values but not the relationship between these as Entries<Obj>
is ["a" | "b" | "c", number | string]
.
type Entry<O, K extends keyof O> = [K, O[K]] type Entries<O> = Entry<O, keyof O>[]
Here the definition of Entry
works as expected eg. Entry<Obj, "a">
is ["a", number]
but the application of it in the second line with keyof O
as the second type variable leads again to the same result as the first try.
Use Typescript Map for Storing the Key-Value pair. Calling the object with the key will return the value for that particular pair. We can also store multiple values in a single key. The insertion order is preserved in the Typescript Map Key value.
The keys of an object is the list of property names. The values of an object is the list of property values. The entries of an object is the list of pairs of property names and corresponding values.
Use the find () method to get the key by its value. Both of the examples in the code snippet get an object's key by value. We used the Object.keys method in the first example. The method returns an array of the object's keys. However, note that TypeScript types the return value of the Object.keys () method as string [].
Typescript comes up with functions that can be used for writing scripts. A key-value pair is a wonderful functionality in an object-oriented programming approach that can be used in Typescript for generating values. These key-value pairs in Typescript are present in the Typescript Object. The values can be function, an array of objects, etc.
TypeScript is telling us that we can't index the object with any string key, it has to be name, department or country. This is why we used a type assertion to type the return value of the Object.keys () method. Now the key parameter in the find method is a union type of the objects keys, so everything works as expected.
If we wanted to iterate over that objet properties in JavaScript we could simply do the following: Unfortunately, in TypeScript that would give the following error. obj [property]: Element implicitly has an ‘any’ type because expression of type ‘string’ can’t be used to index type ‘ { foo: string; bar: string; }’.
Here's a solution, but beware when using this as a return type for Object.entries
; it is not always safe to do that (see below).
When you want to pair each key with something dependent on that key's type, use a mapped type:
type Entries<T> = { [K in keyof T]: [K, T[K]]; }[keyof T][]; type Test = Entries<Obj>; // (["a", number] | ["b", string] | ["c", number])[]
The second version, which has a tuple type containing the properties instead of a union, is much harder to construct; it is possible to convert a union to a tuple but you basically shouldn't do it.
The third version is manageable, but a bit more complicated than the first version: you need PickByValue
from this answer.
type Entries3<T> = { [K in keyof T]: [keyof PickByValue<T, T[K]>, T[K]] }[keyof T][]; type Test3 = Entries3<Obj>; // (["a" | "c", number] | ["b", string])[]
Playground Link
I guess I should also explain why Typescript doesn't give a stronger type to Object.entries
. When you have a type like type Obj = {a: number, b: string, c: number}
, it's only guaranteed that a value has those properties; it is not guaranteed that the value does not also have other properties. For example, the value {a: 1, b: 'foo', c: 2, d: false}
is assignable to the type Obj
(excess property checking for object literals aside).
In this case Object.entries
would return an array containing the element ['d', false]
. The type Entries<Obj>
says this cannot happen, but in fact it can happen; so Entries<T>
is not a sound return type for Object.entries
in general. You should only use the above solution with Object.entries
when you yourself know that the values will have no excess properties; Typescript won't check this for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With