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'
});