Support known possible keys in Object.entries and Object.fromEntries #35745
Comments
The case of @wucdbm I recommend removing the |
Personal stab at typing it, it gets kind of complex, not sure if there is a simpler approach type UnionToIntersection<T> = (T extends T ? (p: T) => void : never) extends (p: infer U) => void ? U : never
type FromEntries<T extends readonly [PropertyKey, any]> = T extends T ? Record<T[0], T[1]> : never;
type Flatten<T> = {} & {
[P in keyof T]: T[P]
}
function fromEntries<V extends PropertyKey, T extends [readonly [V, any]] | Array<readonly [V, any]>>(entries: T): Flatten<UnionToIntersection<FromEntries<T[number]>>> {
return null!;
}
let o = fromEntries([["A", 1], ["B", "1"], [1, true]])
// let o: {
// A: number;
// B: string;
// 1: boolean;
// } Or without any helper types (can't wait for the SO questions as to what this does function fromEntries<V extends PropertyKey, T extends [readonly [V, any]] | Array<readonly [V, any]>>(entries: T):
(((T[number] extends infer Tuple ? Tuple extends [PropertyKey, any] ? Record<Tuple[0], Tuple[1]> : never : never) extends
infer FE ? (FE extends FE ? ((p: FE) => void) : never) extends (p: infer U) => void ? U : never : never) extends
infer R ? { [P in keyof R] : R[P] }: never)
{
return null!;
}
let o = fromEntries([["A", 1], ["B", "1"], [1, true]])
// let o: {
// A: number;
// B: string;
// 1: boolean;
// } |
@MicahZoltu Fair enough. In that case, I guess the For example,
would generate (once per type) a function that takes an object and returns the fields of I stumbled upon https://www.npmjs.com/package/typescript-is and #14419 today. Could use its source code as a starting point if 14419 is accepted and its easy to plug into TS for code generation. WDYT? |
Something similar to |
Original comment updated. Furthermore, due to #31393 imo it makes sense to go with
|
What is the status on this? |
Often you can achieve the desired result with a pattern like this: const fruits = [ 'apple', 'banana', 'cherry' ] as const
type Fruits = (typeof fruits)[number]
type FruitBasket = Record<Fruits, number>
function countFruits(fruitBasket: FruitBasket) {
let totalFruits = 0
for (const fruit of fruits) {
totalFruits += fruitBasket[fruit]
}
return totalFruits
}
countFruits({ apple: 5, banana: 7, cherry: 3 }) // returns: 15
const produceBasket = { apple: 5, banana: 2, cherry: 1, asparagus: 7 }
countFruits(produceBasket) // returns: 8; note it didn't count the asperagus |
@MicahZoltu Good point. That could come in handy in several of the use-cases the .entries typing proposal was trying to solve. Does anybody know a use-case where |
Can TypeScript at least provide a type-safe version of Here keys are known to be of K, but the current signature treats them as strings. |
Search Terms
Object.entries, Object.fromEntries
Suggestion
Add
see #12253 (comment)entries<E extends PropertyKey, T>(o: { [K in E]: T } | ArrayLike<T>): [E, T][];
to Object.entries inlib.es2017.object.d.ts
and
fromEntries<K extends PropertyKey, T = any>(entries: Iterable<readonly [K, T]>): { [k in K]: T };
to Object.fromEntries inlib.es2019.object.d.ts
OR
fromEntries<K extends string, T = any>(entries: Iterable<readonly [K, T]>): { [k in K]: T };
extends string for now until #31393 is resolved in terms of the"keyofStringsOnly": true
compiler option, which would disallow number and symbol.#31393 is a related issue that suggests the same addition @ fromEntries
Any other research lead me to #12253 (comment)
Use Cases
Basically, I'd like to map an object with
known finite number of fields
to an object with thesame keys
, but wherethe values are of different type
(in the example below - the values are transformed from an object containing label: string and rating: number to number)Examples
Example repository at https://github.com/wucdbm/typescript-object-entries-key-type
Commenting out the two suggested additions in
src/types/es.d.ts
leads to two errors in index.ts (Please have a look at the types insrc/types/rating.d.ts
)Object.entries(rating.stars).map((v: [RatingFields, RatingWithLabel]) => {
RatingFields has no sufficient overlap with string, where because ofrating.stars
's index signature, the key can only be one of the values of RatingFieldsObject.fromEntries
complains that the keys ofRatingFields
are missing. But in this case, the first element of the returned array can only be of typeRatingFields
I'm leaving the first checklist option unticked. I am unsure whether this wouldn't be a breaking change for TypeScript code in some situations. I personally haven't encountered one, and have had the same es.d.ts file, found in the example repo, in our project, in order to prevent build errors.
Would be nice if someone with more experience in TS's internals had a look at this. Particularly if it woul lead to any regressions.
Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: