如何创建属性名由用户自定义的TypeScript interface接口?
问题解决方法
报错根本原因
TypeScript 类型系统完全在静态编译阶段执行,所有类型计算会在代码运行前完成,因此运行时定义的普通变量值不能直接放到类型声明位置使用,这是触发 ts(2749) 错误的核心原因。
第二个报错 Exported type alias 'renameProps' has or is using private name 'val' 是因为你定义的 renameProps 类型直接在内部引用了作用域内的局部变量 val 的类型,如果 val 未导出,导出 renameProps 时就会触发作用域校验错误。
正确实现方案
场景1:根据自定义属性名映射生成目标类型
对应你给出的示例需求,基于 userDefinedPropNames 映射生成目标接口的写法如下:
// 给配置对象加 as const 断言,保留内部字符串的字面量类型,否则会被推导为宽泛的string类型 const userDefinedPropNames = { xVal: 'somestring', yVal: 'anotherstring', group: 'athirdstring' } as const interface PreData { xVal: number, yVal: number, group: string } // 先拿到配置对象的类型 type PropNameMap = typeof userDefinedPropNames // 映射生成最终的Data类型 type Data = { [K in keyof PreData as PropNameMap[K]]: PreData[K] }
此时生成的 Data 类型和你示例要求的完全一致:{ somestring: number; anotherstring: number; athirdstring: string }。
场景2:单个动态键的场景
对应你原来使用单个val作为键的需求,修改写法如下:
// 加as const保留字面量类型 const val = 'asdf' as const // 用typeof val拿到值对应的类型,传入Record type Data = Record<typeof val, number> // 映射类型写法也需要把替换键做成泛型参数,避免内部引用外部变量导致作用域错误 type RenameProps<Type, NewKey extends string | number | symbol> = { [Property in keyof Type as NewKey]: Type[Property] } // 调用时传入typeof val作为泛型参数 type Data2 = RenameProps<PreData, typeof val>
额外注意事项
如果属性名是完全运行时才能拿到的动态值(比如后端接口返回、用户输入框输入),编译阶段无法拿到精确的字面量值,这种场景无法生成精确的固定类型,只能用Record<string, unknown>等宽泛类型标注,搭配运行时校验逻辑处理即可,因为TS类型会在编译后全部擦除,无法响应运行时的动态值变化。
内容的提问来源于stack exchange,提问作者Faero
相关产品推荐
相关产品推荐

