How to have TS infer a callback in a generic builder function? How to have TS infer a callback in a generic builder function? typescript typescript

How to have TS infer a callback in a generic builder function?


Try declare Record<K, number> as second generic type.

playground

declare function makeObj<K extends string, T extends Record<K, number> = Record<K, number>>(  builder: (ref: (k: K) => number) => T): Tconst obj1 = makeObj(() => ({ x: 1, y: 2 }));const obj2 = makeObj(ref => ({ x: 1, y: ref("invalid key, only x or y") }));const obj3 = makeObj(ref => ({ x: 1, y: ref("x") }));

Limitation

Well, as @kaya3 commented below.This resolution can only infer the return type.It still cannot find the invalid key unless explicitly set generic type.

// error will shown when given explicit generic typeconst obj2 = makeObj<'x' | 'y'>(ref => ({x: 1, y: ref("invalid key, only x or y")}));


type Ref<Obj> = {  ref<Key extends string & keyof Obj>      (k:`${Key}`):Obj[Key]};declare function makeObject<Type>(obj: Type): Type & Ref<Type>;const person = makeObject({  firstName: "Saoirse",  lastName: "Ronan",  age: 26});person.ref('firstName') // (method) ref<"firstName">(k: "firstName"): string// Argument of type '"firstNme"' is not assignable to // parameter of type '"firstName" | "lastName" | "age"'.ts(2345)person.ref('firstNme') // ERRORperson.ref('age') // (method) ref<"age">(k: "age"): number

Reference "String Unions in Types"

Unfortunately you can't access ref when you are declaring the object in the call to makeObject. Fortunately, the native Javascript approximation is pretty good anyway.