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

如何在子作用域中使用类型守卫定义的Props而无需重复定义类型

解决React/TypeScript联合类型Props解构后变量隐式any问题

方案1:使用带判别式的状态对象(推荐)

通过立即执行函数生成带有类型判别式的状态对象,让TypeScript自动推断字段类型,无需手动声明:

type WrongInfoProps = (
  | WrongInfoCompanyProps
  | WrongInfoPersonProps
  | WrongInfoBranchProps
) & WrongInfoCallbackProps;

interface WrongInfoCallbackProps {
  onClose: (isModalOpen?: boolean) => void;
}

interface WrongInfoCompanyProps {
  companyId: number;
}

interface WrongInfoBranchProps {
  branchId: number;
  branchName: string;
  companyId: number;
  parentName: string;
}

interface WrongInfoPersonProps {
  employmentId: number;
  execId: number;
  companyName: string;
}

export default function App(props: WrongInfoProps) {
  // 用立即执行函数生成带判别式的状态对象
  const state = (() => {
    if ("branchId" in props) {
      const { branchId, companyId, branchName, parentName } = props;
      return { type: "branch", branchId, companyId, branchName, parentName };
    } else if ("companyId" in props) {
      const { companyId } = props;
      return { type: "company", companyId };
    } else {
      const { execId, employmentId, companyName } = props;
      return { type: "person", execId, employmentId, companyName };
    }
  })();

  const renderCompany = () => {
    // 通过判别式缩小类型范围,TypeScript自动推断companyId为number
    if (state.type === "branch" || state.type === "company") {
      return <div>{state.companyId}</div>;
    }
    return null; // 处理无companyId的场景
  };

  return (
    <div className="App">
      <h1>{renderCompany()}</h1>
      <div>{state.type !== "person" && state.companyId}</div>
    </div>
  );
}

优势:

  • 完全利用TypeScript类型推断,无需手动声明变量类型
  • 通过判别式type明确区分不同Props类型,避免类型歧义
  • 变量作用域清晰,无隐式any问题

方案2:复用已有Props类型声明变量

如果不想大幅改动现有代码,可从已有的Props接口中提取字段类型,避免重复定义:

// ... 类型定义部分不变

export default function App(props: WrongInfoProps) {
  // 从已有接口提取类型,避免重复写number
  let companyId: WrongInfoCompanyProps["companyId"] | undefined;
  let branchId: WrongInfoBranchProps["branchId"] | undefined;
  let branchName: WrongInfoBranchProps["branchName"] | undefined;
  let parentName: WrongInfoBranchProps["parentName"] | undefined;
  let execId: WrongInfoPersonProps["execId"] | undefined;
  let employmentId: WrongInfoPersonProps["employmentId"] | undefined;
  let companyName: WrongInfoPersonProps["companyName"] | undefined;

  if ("branchId" in props) {
    ({ branchId, companyId, branchName, parentName } = props);
  } else if ("companyId" in props) {
    ({ companyId } = props);
  } else if ("execId" in props) {
    ({ execId, employmentId, companyName } = props);
  }

  const renderCompany = () => {
    // 判断变量是否存在,TypeScript自动缩小类型范围
    if (companyId !== undefined) {
      return <div>{companyId}</div>;
    }
    return null;
  };

  return (
    <div className="App">
      <h1>{renderCompany()}</h1>
      <div>{companyId}</div>
    </div>
  );
}

通过WrongInfoCompanyProps["companyId"]复用已有类型定义,既避免重复写number,又让TypeScript明确变量类型,解决隐式any问题。

方案3:直接在函数内做类型守卫

如果仅需在特定函数中使用companyId,可直接在函数内对props做类型守卫,无需提前解构:

// ... 类型定义部分不变

export default function App(props: WrongInfoProps) {
  const renderCompany = () => {
    // 直接在函数内判断props类型,TypeScript自动推断companyId类型
    if ("companyId" in props) {
      return <div>{props.companyId}</div>;
    }
    return null;
  };

  return (
    <div className="App">
      <h1>{renderCompany()}</h1>
      <div>{("companyId" in props) && props.companyId}</div>
    </div>
  );
}

该方案最简洁,适合无需提前解构大量字段的场景,直接利用in操作符做类型守卫即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 14:20:22