首页 > 解决方案 > 使用 Typescript 反应功能组件:Typescript 不理解更改的属性类型

问题描述

我将一个可以是字符串或对象的道具传递给反应功能组件,下面是一个示例。它无需打字稿即可工作。但是,当我添加打字稿时,它似乎不明白道具(例如下面的 helpMessage)可以是字符串或对象。

我收到这个错误 TS2339: Property 'message' does not exist on type 'string | HelpMessage'.   Property 'message' does not exist on type 'string'.

import React, { FC } from 'react';

interface HelpMessage {
  headerText?: string;
  footerText?: string;
  message?: string;
}

interface FieldProps {
  name: string;
  helpMessage?: string | HelpMessage;
}

const ConditionalPropsComponent: FC<FieldProps> = ({ name, helpMessage }) => {
  const helpMessageIsString = typeof helpMessage === 'string';
  const helpText =
    helpMessage && helpMessageIsString ? helpMessage : helpMessage?.message;

  return (
    <div>
      {helpText && !helpMessageIsString && (
        <div>
          <p>{helpMessage?.headerText}</p>
          <p>{helpMessage?.message}</p>
          <p>{helpMessage?.footerText}</p>
        </div>
      )}
      {helpText && helpMessageIsString && <p>{helpText}</p>}
    </div>
  );
};

export default ConditionalPropsComponent;

错误出现在下面屏幕截图中红色摆动线的位置:

在此处输入图像描述

我创建了一个代码沙箱,以便您可以看到问题。 https://codesandbox.io/s/github/nfabacus/React-typescript-dynamic-type-issue/tree/main/?file=/src/index.tsx:217-226

基本上,提取条件以const helpMessageIsString = typeof helpMessage === 'string';引发类型错误,但如果我将它们中的每一个替换为typeof helpMessage === 'string',错误就会消失,但这是重复的..

此外,下面的作品但感觉很hacky - helpMessage 是HelpMessage 或未定义。当我传递字符串时,它既不是 HelpMessage 对象也不是未定义的,但打字稿不会抱怨..这很奇怪。

interface HelpMessage {
  headerText?: string;
  footerText?: string;
  message?: string;
}

interface FieldProps {
  name: string;
  helpMessage?: HelpMessage;
}

const ConditionalPropsComponent: React.FC<FieldProps> = ({
  name,
  helpMessage
}) => {
  const helpMessageIsString = typeof helpMessage === 'string';
  const helpText = helpMessageIsString ? helpMessage : helpMessage?.message;
....

Typescript 很棒,但在这种特殊情况下,我对 Typescript 感到有点失望,如果没有一个好的解决方案......

标签: reactjstypescripttypesreact-props

解决方案


您在此示例中缺少的是Type AssertionType Inference

Typescript 是一个编译器,它不能在运行时中断类型。

当你编写这样的代码时,Typescript 将helpMessageIsString类型推断为boolean而不是“如果它是一个真实的布尔值那么helpMessage是字符串”。

// helpMessageIsString is boolean
const helpMessageIsString = typeof helpMessage === "string";

// Typescript can't interrupt if the boolean has a meaning for true
//                                      v string | HelpMessage
const helpText = helpMessageIsString ? helpMessage : helpMessage?.message;

使其工作的最简单方法是通过条件块使用类型推断:

if (typeof helpMessage === "string") {
  // In this scope, helpMessage is a STRING
} else {
  // In this scope, helpMessage is of type HelpMessage
}

对于其他不可读的解决方案,只需在类型断言文档中选择一个可用的 API。


推荐阅读