I’ve code like this (TS Playground):
const createComp = <T extends {
modifiers: {
[key: string]: string;
};
defaultMods: keyof T["modifiers"];
}
>(com: T) => com;
const style = createComp({
modifiers: {
blue: 'blue',
red: 'red'
},
defaultMods: 'red' // correct. defaultMods type is 'blue' | 'red'
});
It infer defaultMods
type to 'blue' | 'red'
as I expected.
But when I try to extract the extends
type to Component
type, like this (TS Playground):
type Component = {
modifiers: {
[key: string]: string;
};
defaultMods: keyof Component["modifiers"];
}
const createComp = <T extends Component>(com: T) => com;
const style = createComp({
modifiers: {
blue: 'blue',
red: 'red'
},
defaultMods: '' // defaultMods type is string
});
It doesn’t return defaultMods
type as 'blue' | 'red'
. Did I miss something?
>Solution :
keyof Component["modifiers"]
always resolves to string
. You will need an extra type parameter to Component
to represent the modifiers, and infer that in your function:
type Component<TModifiers extends Record<string, string>> = {
modifiers: TModifiers;
defaultMods: keyof TModifiers;
}
const createComp = <TModifiers extends Record<string, string>>(com: Component<TModifiers>) => com;
const style = createComp({
modifiers: {
blue: 'blue',
red: 'red'
},
defaultMods: '' // it should be 'blue' | 'red'
});