如何使用格式化字符串作为键从只读对象中取值?
存在一个只读对象errorMessages和一些字段,每个字段在errorMessages中对应多条错误信息,但无法使用格式化字符串作为键从该只读对象中取值。
代码示例:
import { useState } from "react"; const errorMessages = { emailInvalid: "Invalid email address", emailAlreadyExists: "This email is already exists", phoneInvalid: "Invalid phone number", phoneNotAllowed: "Phone region is not allowed" } as const; const fields = ["email", "phone"]; export default function App() { const [error, setError] = useState(""); const handleClick = (field: string) => { const errorKey = `${field}Invalid`; setError(errorMessages[errorKey]); // 此处报错 }; return ( <div> <h1>{error}</h1> {fields.map((field) => ( <button key={field} onClick={() => handleClick(field)}> {field} error </button> ))} </div> ); }
报错信息:
Element implicitly has an 'any' type because expression of type
'string' can't be used to index type '{ readonly required: "This field
is required"; readonly emailInvalid: "Invalid email address"; readonly
phoneInvalid: "Invalid phone number"; }'. No index signature with a
parameter of type 'string' was found on type '{ readonly required:
"This field is required"; readonly emailInvalid: "Invalid email
address"; readonly phoneInvalid: "Invalid phone number"; }'.ts(7053)
需要解决两个问题:
- 能否在不修改
errorMessages的前提下修复类型报错? - 为何存在类型报错的代码仍能正常运行?
errorMessages) 因为errorMessages被as const标记为只读,TypeScript会严格限制其索引必须是自身的字面量键类型,而${field}Invalid被推断为宽泛的string类型,无法匹配具体的键。以下是几种可行的修复方式:
方式1:类型断言为目标键类型
直接将生成的键断言为errorMessages的键类型,告诉TypeScript这个键是合法的:
const handleClick = (field: string) => { const errorKey = `${field}Invalid` as keyof typeof errorMessages; setError(errorMessages[errorKey]); };
注意:如果传入的field生成的键不在errorMessages中,运行时会得到undefined,需要确保field的取值范围是安全的。
方式2:缩小字段的类型范围
把fields数组的类型改为字面量联合类型,让field的类型从string变成具体的"email" | "phone",再配合类型断言:
// 用as const把数组转为只读字面量数组 const fields = ["email", "phone"] as const; const handleClick = (field: typeof fields[number]) => { const errorKey = `${field}Invalid` as keyof typeof errorMessages; setError(errorMessages[errorKey]); };
这种方式更安全,TypeScript会检查field的取值,避免传入无效字段。
方式3:用类型守卫验证键的合法性
添加类型守卫函数,确保生成的键确实存在于errorMessages中,同时让TypeScript自动推断类型:
const isErrorKey = (key: string): key is keyof typeof errorMessages => { return key in errorMessages; }; const handleClick = (field: string) => { const errorKey = `${field}Invalid`; if (isErrorKey(errorKey)) { setError(errorMessages[errorKey]); } else { // 处理无效键的情况,比如设置默认错误信息 setError("Invalid field error"); } };
TypeScript的报错属于编译时类型检查,它的作用是提前提示开发者潜在的类型安全问题,但不会阻止代码被编译为JavaScript执行。只要代码本身符合JavaScript语法规范,即使存在TypeScript类型错误,编译后的JS代码依然能正常运行。
内容的提问来源于stack exchange,提问作者j-0-n-e-z

