cefn
cefn

Reputation: 3341

Typescript fails to infer key-value pairs from lookup

In the below example I try to map to a list of InnerNamed typed values from a lookup of typed values, (see InnerNamed definition) but the inferred type is way too broad.

In the end, the type of resolved should be (InnerNamed<"Cefn", 3> | InnerNamed<"Joe", "hey">)[] equivalent to ({Cefn:3} | {Joe:"hey"})[]. It is instead inferred as InnerNamed<string, unknown>[]

Is there anything I can do to improve inference here?

See also the playground to experiment interactively.

/** Assert type of Object.entries */
type InferEntry<Lookup, K extends keyof Lookup = keyof Lookup> = {
  [K in keyof Lookup]: [K, Lookup[K]];
}[K];

/** Type for an object containing a single, named entry (common paradigm for javascript records like
 * ```
 * {
 *  MyItem:{some:"value"}
 * }
 * ```
 */
type InnerNamed<InnerName extends string, T> = { [k in InnerName]: T };
const namedProps: InnerNamed<"Cefn", {hi:number}> = {
  // autocompletes correctly
  Cefn: {
    hi: 3
  }
};

/** Map to InnerNamed types given a lookup of named types. */

type Resolved<Name extends string, Resolver extends Record<Name, any>> = {
  [N in Name]: InnerNamed<Name, Resolver[Name]>;
}[Name];

function createResolved<Name extends string, Resolver extends Record<Name, any>>(resolver:Resolver){
  return Object.entries(resolver).map((entry) => {
    const [name, value] = entry as InferEntry<typeof resolver>
    return {
      [name]:value
    }
  }) as Resolved<Name, Resolver>[]
}

// the type of resolved should be (InnerNamed<"Cefn", 3> | InnerNamed<"Joe", "hey">)[]
// i.e. ({Cefn:3} | {Joe:"hey"})[] 
// but is instead InnerNamed<string, unknown>[]
const resolved = createResolved({
  Cefn:3,
  Joe:"hey"
});


// printing out the actual structure of resolved
// shows the narrower type would be satisfied
// even though it was not inferred
console.log({resolved})
//   "resolved": [
//     {
//       "Cefn": 3
//     },
//     {
//       "Joe": "hey"
//     }
//   ]
// } 

Upvotes: 1

Views: 70

Answers (0)

Related Questions