You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript索引类型错误:字符串表达式无法索引指定类型

React中TypeScript索引类型错误的解决方法

问题场景

在React组件中通过useState定义basicDetails和errorMessage状态对象后,编写validation函数遍历errorMessage的键时,触发TypeScript错误:

元素隐式拥有'any'类型,因为字符串类型的表达式无法用于索引类型 '{ companyName: string; pocName: string; pocEmail: string; pocMobile: string; businessCard: { file: string; type: string; url: string; }; companyBaseAddress: { line1: string; line2: string; city: string; region: string; zip_code: string; country: string; }[]; }'。未找到接受string类型参数的索引签名。

原代码示例

const [basicDetails, setBasicDetails] = useState({
  companyName: "",
  pocName: "",
  pocEmail: "",
  pocMobile: "",
  businessCard: { file: "", type: "", url: "" },
  companyBaseAddress: [defaultAddress]
});

const [errorMessage, setErrorMessage] = useState({
  companyName: "",
  pocName: "",
  pocEmail: "",
  pocMobile: "",
  businessCard: { file: "", type: "", url: "" },
  companyBaseAddress: [defaultAddress]
});

const validation = () => {
  Object.keys(errorMessage).map((field => basicDetails[field] === "" ?
    setErrorMessage(prevState => ({ ...prevState, [field]: "Can not be Empty" })) : null));
};

问题原因

Object.keys()返回的是string[]类型,TypeScript无法确认这些字符串就是basicDetails和errorMessage的合法键名,因此索引时会抛出类型错误。另外原代码还存在逻辑问题:businessCard是对象、companyBaseAddress是数组,它们永远不会等于空字符串,直接判断会无效。

解决方法

方法1:定义类型别名并断言键类型

先为状态对象定义明确的类型,再将Object.keys()的结果断言为类型的键数组,同时增加类型判断避免无效验证:

// 定义基础详情类型
type BasicDetails = {
  companyName: string;
  pocName: string;
  pocEmail: string;
  pocMobile: string;
  businessCard: { file: string; type: string; url: string };
  companyBaseAddress: { line1: string; line2: string; city: string; region: string; zip_code: string; country: string }[];
};

// 定义错误信息类型,与BasicDetails结构匹配
type ErrorMessage = {
  [K in keyof BasicDetails]: BasicDetails[K] extends string ? string : 
    BasicDetails[K] extends object ? typeof BasicDetails['businessCard'] :
    typeof BasicDetails['companyBaseAddress'];
};

// 初始化状态时指定类型
const [basicDetails, setBasicDetails] = useState<BasicDetails>({
  companyName: "",
  pocName: "",
  pocEmail: "",
  pocMobile: "",
  businessCard: { file: "", type: "", url: "" },
  companyBaseAddress: [defaultAddress]
});

const [errorMessage, setErrorMessage] = useState<ErrorMessage>({
  companyName: "",
  pocName: "",
  pocEmail: "",
  pocMobile: "",
  businessCard: { file: "", type: "", url: "" },
  companyBaseAddress: [defaultAddress]
});

const validation = () => {
  // 将field断言为BasicDetails的合法键
  (Object.keys(errorMessage) as Array<keyof BasicDetails>).map(field => {
    // 仅验证字符串类型的字段
    if (typeof basicDetails[field] === 'string' && basicDetails[field] === "") {
      setErrorMessage(prevState => ({ ...prevState, [field]: "Can not be Empty" }));
    }
    return null;
  });
};

方法2:手动指定需要验证的字段数组

直接创建包含合法键的数组,TypeScript能准确推断类型,同时避免遍历无关字段:

// 先定义BasicDetails类型(同方法1)
type BasicDetails = { /* ... */ };

const [basicDetails, setBasicDetails] = useState<BasicDetails>({ /* ... */ });
const [errorMessage, setErrorMessage] = useState<ErrorMessage>({ /* ... */ });

const validation = () => {
  // 只列出需要验证的字符串类型字段
  const fieldsToValidate: Array<keyof BasicDetails> = ['companyName', 'pocName', 'pocEmail', 'pocMobile'];
  
  fieldsToValidate.forEach(field => {
    if (basicDetails[field] === "") {
      setErrorMessage(prev => ({ ...prev, [field]: "Can not be Empty" }));
    }
  });
};

注意事项

  • 不要给BasicDetails添加[key: string]: any的索引签名,这会丢失TypeScript的类型检查能力。
  • 必须区分字段类型,不要对非字符串类型的字段做空字符串判断,避免无效逻辑。

内容的提问来源于stack exchange,提问作者Shiva Giri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:26:05