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

React+TypeScript表单组件类型报错:如何修复属性不存在问题?

TypeScript类型错误修复:React表单状态类型指定问题

问题代码

import React, { useState } from 'react';

interface AddressForm {
  name: string;
  address: string;
}

interface PhoneForm {
  name: string;
  phoneNumber: number;
}

const Example = () => {
  let isCase1 = true;

  const [formContent, setformContent] = useState<AddressForm | PhoneForm | {}>(
    {}
  );

  return (
    <form>
      <input type="text" name="name" value={formContent.name} />
      {isCase1 ? (
        <input type="text" name="name" value={formContent.address} />
      ) : (
        <input
          type="number"
          name="phoneNumber"
          value={formContent.phoneNumber}
        />
      )}
    </form>
  );
};

export default Example;

报错信息

Property 'phoneNumber' does not exist on type '{} | AddressForm | PhoneForm'.
  Property 'phoneNumber' does not exist on type '{}'.ts(2339)

报错核心原因:formContent的类型包含空对象{},而空对象没有name、address、phoneNumber这些属性,TypeScript无法确定当前状态的具体类型,因此抛出类型检查错误。


解决方案

方案1:移除空对象类型,匹配初始表单类型初始化

直接将useState的类型限定为AddressForm | PhoneForm,并根据isCase1的初始值给状态赋对应类型的初始值,消除空对象带来的类型歧义。

修改后的代码:

import React, { useState } from 'react';

interface AddressForm {
  name: string;
  address: string;
}

interface PhoneForm {
  name: string;
  phoneNumber: number;
}

const Example = () => {
  const isCase1 = true;

  // 根据isCase1初始值设置对应类型的初始状态
  const [formContent, setformContent] = useState<AddressForm | PhoneForm>(
    isCase1 ? { name: '', address: '' } : { name: '', phoneNumber: 0 }
  );

  return (
    <form>
      <input type="text" name="name" value={formContent.name} />
      {isCase1 ? (
        <input type="text" name="address" value={(formContent as AddressForm).address} />
      ) : (
        <input
          type="number"
          name="phoneNumber"
          value={(formContent as PhoneForm).phoneNumber}
        />
      )}
    </form>
  );
};

export default Example;

通过类型断言as AddressForm/as PhoneForm,明确告诉TypeScript当前分支下formContent的具体类型,消除类型检查错误。

方案2:使用可辨识联合类型(更严谨的类型区分)

给两个表单接口添加共同的辨识字段(比如formType),让TypeScript能自动根据该字段区分类型,无需手动断言。

修改后的代码:

import React, { useState } from 'react';

interface AddressForm {
  formType: 'address';
  name: string;
  address: string;
}

interface PhoneForm {
  formType: 'phone';
  name: string;
  phoneNumber: number;
}

type FormContent = AddressForm | PhoneForm;

const Example = () => {
  const [isCase1, setIsCase1] = useState(true);
  // 初始化对应类型的状态
  const [formContent, setformContent] = useState<FormContent>(
    isCase1 ? { formType: 'address', name: '', address: '' } : { formType: 'phone', name: '', phoneNumber: 0 }
  );

  return (
    <form>
      <input type="text" name="name" value={formContent.name} />
      {isCase1 ? (
        <input type="text" name="address" value={formContent.address} />
      ) : (
        <input
          type="number"
          name="phoneNumber"
          value={formContent.phoneNumber}
        />
      )}
      {/* 可选:添加切换按钮演示类型切换 */}
      <button type="button" onClick={() => setIsCase1(!isCase1)}>
        切换表单类型
      </button>
    </form>
  );
};

export default Example;

此时TypeScript会通过isCase1和formType的关联自动推断分支内的formContent类型,无需额外断言,类型检查更严谨。

方案3:使用类型守卫函数

如果需要更灵活的类型判断,可以编写类型守卫函数来明确formContent的具体类型:

import React, { useState } from 'react';

interface AddressForm {
  name: string;
  address: string;
}

interface PhoneForm {
  name: string;
  phoneNumber: number;
}

// 类型守卫:判断是否为AddressForm
function isAddressForm(form: AddressForm | PhoneForm): form is AddressForm {
  return 'address' in form;
}

// 类型守卫:判断是否为PhoneForm
function isPhoneForm(form: AddressForm | PhoneForm): form is PhoneForm {
  return 'phoneNumber' in form;
}

const Example = () => {
  const isCase1 = true;

  const [formContent, setformContent] = useState<AddressForm | PhoneForm>(
    isCase1 ? { name: '', address: '' } : { name: '', phoneNumber: 0 }
  );

  return (
    <form>
      <input type="text" name="name" value={formContent.name} />
      {isCase1 ? (
        isAddressForm(formContent) && <input type="text" name="address" value={formContent.address} />
      ) : (
        isPhoneForm(formContent) && <input
          type="number"
          name="phoneNumber"
          value={formContent.phoneNumber}
        />
      )}
    </form>
  );
};

export default Example;

类型守卫函数会让TypeScript在条件判断后自动缩小类型范围,确保属性访问的安全性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 18:31:09