给配置对象写了 [k: string]: string 的索引签名,想用 keyof 拿具体键名生成下拉选项,结果类型是 string | number,下拉里一个值都渲染不出来。乍看像缓存或者权限的锅,追下去往往不是。
const cfg = { a: '1', b: '2' } as const;
type K = keyof typeof cfg; // 'a' | 'b'
type Wide = { [k: string]: string } & { a: string; b: string };
追下去是这么回事:索引签名描述的是任意字符串键,keyof 只能返回它的键类型,拿不到字面量键名。声明成宽索引之后,原有字段的类型也一起被抹平。
「keyof 索引签名」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。
能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。报错里带路径的,先去看那个路径在不在、权限对不对。
具体做法是,把索引签名拆掉 只保留具体字段;确实需要动态键 就单独定义一个宽类型再用交叉合并;要字面量键名 就在 as const 之后用 keyof typeof 取。
验收就看一点,keyof 的结果是 a 和 b 两个字面量 下拉能渲染出选项 取值类型也不再宽泛。
