TL;DR
Question: How can I create a type converter that gets the defined keys of objects typed with types with index signatures?
I want to create a type "converter" in TypeScript, which gets a type A and returns a new type B that have keys as all defined keys in A and accepts only string as values, like in the example:
type AToB<
T,
K extends keyof T = keyof T
> = { [id in K]: string };
const a = {
x : {}
}
const b : AToB<typeof a> = {
x : "here it works"
}
But when I use this in a object that already has a type with index signature defined, the keyof doesn't get the defined keys, e.g.:
type AWithSig = {
[id : string]: {};
}
const aSig : AWithSig = {
y: {},
z: {}
}
const bSig : AToB<typeof aSig> = {
y : "here the keys",
z : "are not shown :("
}
I tried it in the TSPlayground (link here) and it doesn't recognize the defined keys in aSig.



The problem isn't with
AtoB, but with the type ofaSig.When you annotate a variable with a (non-union) type, that's the type of the variable. It doesn't gain any more specific information from the expression with which you initialize the variable.
So by the time you write
const aSig: AWithSig = ⋯you've already lost the type you care about.Presumably the only reason you annotated in the first place was just to check that the type of the initializing expression was a valid
AWithSig. If so, you can instead use thesatisfiesoperator on this expression to perform the check, and then just allow the compiler to infer the type ofaSigafterward:Oops, I made a mistake and the compiler caught it:
And now the type of
aSigiswhich will work as desired with
AtoB:Playground link to code