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

React组件JSX中如何基于isSeller转换用户变量的TS类型?

解决TypeScript中根据isSeller字段区分用户类型的问题

问题背景

在React个人资料页组件中,用户分为普通客户(customer)和卖家(seller)两种角色,卖家拥有ico、firmName等额外属性。当API返回的用户对象isSeller为true时,TypeScript无法自动识别该用户为TSeller类型,导致访问firmName等属性时提示“属性在TCustomer类型中不存在”的错误。

类型定义

import type { TDeliveryInformation } from '../../pages/OrderCreate'

export interface TCustomer {
  firstName: string
  lastName: string
  email: string
  phone: string
  bornDate: string
  isSeller: boolean
  deliveryInformation: TDeliveryInformation
}

export interface TSeller extends TCustomer {
  ico: string
  firmName: string
  // ...其他卖家专属属性
}

现有查询与组件代码

查询代码

import { useQuery } from '@tanstack/react-query'
import { api } from '../../index'
import type { TCustomer, TSeller } from '../../../@types/user/user'

const useMeQuery = () => 
  useQuery({
    queryKey: ['me'],
    queryFn: () => api().get(`me`).json<TCustomer | TSeller>(),
  })

export default useMeQuery

组件示例

import { NavLink, Outlet } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import useMeQuery from '../../api/query/user/useMeQuery'
import Loader from '../../components/reusableComponents/Loader'

const User = () => {
  const { t } = useTranslation()
  const {
    data: userInfo,
    isLoading: userBeingLoaded,
    isError: userError,
  } = useMeQuery()

  if (userBeingLoaded) return <Loader />
  if (userError) return 'Error happened'
  if (!userInfo) return null

  return (
    <div className="wrapper-width mx-auto mt-10">
      <div className="flex">
        <div>
          <h2>
            {userInfo.isSeller
              {/* 此处TypeScript无法识别userInfo为TSeller类型 */}
              ? userInfo.firmName
              : `${userInfo.firstName} ${userInfo.lastName}`}
          </h2>
        </div>
        <Outlet />
      </div>
    </div>
  )
}

export default User

解决方案

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

定义一个类型守卫函数,帮助TypeScript缩小用户类型范围:

// 可放在类型定义文件或组件文件中
function isSeller(user: TCustomer | TSeller): user is TSeller {
  return user.isSeller;
}

在组件中使用该函数进行类型判断:

<h2>
  {isSeller(userInfo) 
    ? userInfo.firmName 
    : `${userInfo.firstName} ${userInfo.lastName}`}
</h2>

方案2:修改类型为区分联合类型(Discriminated Union)

调整类型定义,将isSeller设为区分字段,让TypeScript自动识别类型:

import type { TDeliveryInformation } from '../../pages/OrderCreate'

export interface TCustomer {
  firstName: string
  lastName: string
  email: string
  phone: string
  bornDate: string
  isSeller: false // 明确普通用户的isSeller为false
  deliveryInformation: TDeliveryInformation
}

export interface TSeller extends Omit<TCustomer, 'isSeller'> {
  isSeller: true // 明确卖家的isSeller为true
  ico: string
  firmName: string
  // ...其他卖家专属属性
}

此时无需额外函数,直接通过userInfo.isSeller判断即可让TypeScript自动推断类型:

<h2>
  {userInfo.isSeller
    ? userInfo.firmName
    : `${userInfo.firstName} ${userInfo.lastName}`}
</h2>

方案3:类型断言(快速但不够安全)

如果确定isSeller为true时用户一定是TSeller,可使用类型断言快速解决,但这种方式跳过了TypeScript的类型检查,仅适合临时场景:

<h2>
  {userInfo.isSeller
    ? (userInfo as TSeller).firmName
    : `${userInfo.firstName} ${userInfo.lastName}`}
</h2>

内容的提问来源于stack exchange,提问作者Tomáš Kretek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 11:17:57