Typescript 推断映射中键的类型(同时在映射中键入值)

Typescript 推断映射中键的类型(同时在映射中键入值),typescript,type-inference,Typescript,Type Inference,我想从地图上推断钥匙的类型 我可以成功地做到这一点: const componentStyles={ 按钮:{颜色:'红色'}, 标题:{fontSize:18,线宽:28}, 正文:{fontSize:12,线宽:18}, }; 类型ComponentName=keyof(类型componentStyles); TypeScript将推断: type ComponentName='button'|'heading'|'body'; 但是,我还希望在映射中强制执行值的类型。但当我这么做的时候

我想从地图上推断钥匙的类型

我可以成功地做到这一点:

const componentStyles={
按钮:{颜色:'红色'},
标题:{fontSize:18,线宽:28},
正文:{fontSize:12,线宽:18},
};
类型ComponentName=keyof(类型componentStyles);
TypeScript将推断:

type ComponentName='button'|'heading'|'body';
但是,我还希望在映射中强制执行值的类型。但当我这么做的时候:

界面风格{
颜色?:字符串;
字体大小?:数字;
线宽?:编号;
}
常量组件样式:{[key:string]:Style}={
按钮:{颜色:'红色'},
标题:{fontSize:18,线宽:28},
正文:{fontSize:12,线宽:18},
};
类型ComponentName=keyof(类型componentStyles);
然后TypeScript将推断:

type ComponentName=string | number;

有办法解决这个问题吗?(无需手动写出映射键。)

对于此用例,我建议使用一个助手函数,该函数不会更改
组件样式的推断类型,但只允许您使用正确的属性类型创建对象:

const asComponentStyles = <T extends Record<keyof T, Style>>(t: T) => t;
这是你想要的。让我们确保它在防止不良的
Style
属性方面发挥了作用:

const errorChecking = asComponentStyles({
    okay: { color: 'chartreuse', lineHeight: 123 },
    badColor: { color: 123, lineHeight: 123 }, // error!
    //          ~~~~~ <── 'number' is not assignable to type 'string | undefined'.
    excessPropChecking: { colour: "grey" } // error!
    //   ┌──────────────> ~~~~~~~~~~~~~~
    // Object literal may only specify known properties, 
    // but 'colour' does not exist in type 'Style'.
    // Did you mean to write 'color'?
})
不确定接口值的东西是否是用例的一部分


无论如何,希望这有帮助;祝你好运


您想要的输出是什么?我想让typescript推断
type ComponentName='button'|'heading'|'body'const errorChecking = asComponentStyles({
    okay: { color: 'chartreuse', lineHeight: 123 },
    badColor: { color: 123, lineHeight: 123 }, // error!
    //          ~~~~~ <── 'number' is not assignable to type 'string | undefined'.
    excessPropChecking: { colour: "grey" } // error!
    //   ┌──────────────> ~~~~~~~~~~~~~~
    // Object literal may only specify known properties, 
    // but 'colour' does not exist in type 'Style'.
    // Did you mean to write 'color'?
})
const asComponentStylesIndex = <T extends { [k: string]: Style }>(t: T) => t;

const componentStylesIndex = asComponentStylesIndex({
    button: { color: 'red' },
    heading: { fontSize: 18, lineHeight: 28 },
    body: { fontSize: 12, lineHeight: 18 },
}); // okay
interface MyComponent {
    foo: Style,
    bar: Style
}
declare const myComponent: MyComponent; // value of an interface type

const works = asComponentStyles(myComponent); // okay
const doesntWork = asComponentStylesIndex(myComponent); // error!
//  ┌───────────────────────────────────> ~~~~~~~~~~~
// Index signature is missing in type 'MyComponent'.