I have a type that looks like this:
type Config = {
endpoints: [
{name: "abc", created: false},
{name: "xyz", created: true},
]
}
I have a function that transforms this type into the following:
type Instance = {
abc: {name: "abc", created: false},
xyz: {name: "xyz", created: false},
}
I wrote the following transformation type
type IntersectOf<U extends any> = (U extends unknown ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type Transform<T extends Config, K extends (keyof T)[] = (keyof T)[]> = IntersectOf<{
[key in keyof K]:
K[key] extends keyof T['endpoints']
// here it says "name" can't be used as index of `T["endpoints"][K[key]]`
? Record<T['endpoints'][K[key]]['name'], T['endpoints'][K[key]]>
: never;
}[number]>;
type Instance = Transform<Config>;
I also tried adding a number type guard, and the error goes away but Instance
becomes unknown
. Here is the Transform
type with number typeguard:
type Trasnform<T extends Config, K extends (keyof T)[] = (keyof T)[]> = IntersectOf<{
[key in keyof K]:
K[key] extends keyof T['endpoints']
? K[key] extends number
? Record<T['endpoints'][K[key]]['name'], T['endpoints'][K[key]]>
: never
: never;
}[number]>;
CodePudding user response:
My suggestion would be to write a key-remapping mapped type that acts on the union of element types of the endpoints
property, like this:
type Transform<T extends { name: string }> =
{ [U in T as U['name']]: U }
And then you pass in, not Config
, but the indexed access type Config['endpoints'][number]
corresponding to the element types:
type Instance = Transform<Config['endpoints'][number]>;
That produces this:
/* type Instance = {
abc: {
name: "abc";
created: false;
};
xyz: {
name: "xyz";
created: true;
};
} */
which is what you were looking for.
CodePudding user response:
A proposal (playground):
export type IndicesOf<T> = Exclude<keyof T, keyof any[]>;
type Instance = {
[Idx in IndicesOf<Config["endpoints"]>
as Config["endpoints"][Idx]["name"]]: Config["endpoints"][Idx]
}