我在打字和react 方面遇到了问题.

假设我有以下UNION类型:

type Fruits = 'apple' | 'peach' | 'banana';

我是这样使用它的:

type FoodBaseProps = {
  fruits: Fruits;
  weight: number
  price: number
} 

现在,假设我有一个名为needToPeel的布尔props ,它应该只在水果banana通过时才会被通知;

为了解决这个问题,我做了以下工作:

export type NeedToPeelFruitsProps = FoodBaseProps & {
  fruits: Extract<Fruits, 'banana'>;
  needToPeel?: boolean;
};

至于其他不需要go 皮的水果,我有:

export type DefaultFruitsProps = FoodBaseProps & {
  fruits: Exclude<Fruits, 'banana'>;
};

然后我就有了:

type FoodProps = NeedToPeelFruitsProps | DefaultFruitsProps;

现在,如果我根据这个逻辑做一些断言,我会得到这个(按预期工作):

const testFn = (food: FoodProps) => {
  switch (food.fruits) {
    case 'banana': {
      console.log(food.needToPeel); // No error
      break;
    }

    case 'apple': {
      console.log(food.needToPeel); // TS2339: Property 'needToPeel' does not exist on type 'DefaultFruitsProps'.
      break;
    }

    default:
  }
};

但是,如果我try 在Reaction组件中访问这个needToPeelprops ,我会遇到一些问题:

const Food = ({
  fruits,
  weight,
  price,
  needToPeel, // TS2339: Property 'needToPeel' does not exist on type 'FoodProps'.
}: FoodProps) => {
  return (
    <FoodBase
      fruits={fruits}
      weight={weight}
      price={price}
      needToPeel={needToPeel} // 2 errors below
    />
  )
}

1-TS2769: No overload matches this call.   Overload 1 of 2, '(props: Omit<Omit<Pick<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "key" | keyof HTMLAttributes<...>> & { ...; } & [...]

2-TS2339: Property 'needToPeel' does not exist on type 'FoodProps'.

我认为问题是因为unions 类型只考虑共同的props .因此,needToPeelprops 将不可访问,因为它不在类型之间共享.

我想知道是否有方法能够访问我的Reaction组件中的needToPeel.

推荐答案

我认为问题是因为unions 类型只考虑共同的props .

事实上,当变量被类型化为联合时,其值为the only safe thing we know is that it has the common properties.

只有当TypeScrip对联盟的every个成员有效时,才允许执行操作.例如,如果您有联合string | number,则不能使用仅在string上可用的方法

访问特定属性的唯一安全方法是首先narrow个类型,例如,就像您的"断言"示例中那样.

解决方案是使用代码实现narrow个联合,这与您在不使用类型批注的JavaScript中使用的方法相同.当类型脚本可以根据代码的 struct 为值推导出更具体的类型时,就会发生Narrowing.


如果我试图在Reaction组件中访问这个needToPeelprops ,我会遇到一些问题

这是因为,如果我们对函数参数定义中的Reaction函数组件执行典型的props 析构(如问题示例中所示),则这种析构发生得太早.如果我们想要解构并获得特定的needToPeel属性,它必须发生after类型的缩小.

我认为这种情况是偏离这一标准实践的合法理由:正如所暗示的那样,从函数参数定义中分解props 没有严格的技术要求;对于Reaction函数组件来说,这是一种相当常见的实践;在基于React类的组件中,无论如何我们都必须使用this.props.

Reaction文档中One of the very first examples%的带有props 的组件也不使用析构:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

因此,在您的情况下,您可以很好地将析构推迟到after类型的收缩(甚至根本不析构):

const Food = (props: FoodProps) => {
  // Narrowing
  if (props.fruits === "banana") {
    // Now TS knows that props is a NeedToPeelFruitsProps
    return (
      <FoodBase
        fruits={props.fruits}
        weight={props.weight}
        price={props.price}
        needToPeel={props.needToPeel} // Okay
      />
    );
  }
  // Depending on the signature of <FoodBase>,
  // you could even blindly pass the props,
  // which may or may not have the needToPeel property
  return (
    <FoodBase
      {...props}
    />
  )
}

Typescript相关问答推荐

为什么ESLint抱怨通用对象类型?

在React中实现具有独立页面的嵌套路径的最佳实践是什么?

VS代码1.88.0中未出现自动导入建议

如何在方法中定义TypeScript返回类型,以根据参数化类型推断变量的存在?

TS2339:类型{}上不存在属性消息

从TypeScrip中的其他类型检索泛型类型

Angular 17子路由

寻址对象中路径的泛型类型

在排版修饰器中推断方法响应类型

类型脚本可以推断哪个类型作为参数传递到联合类型中吗?

TypeScrip:从对象中提取和处理特定类型的键

确保对象列表在编译时在类型脚本中具有唯一键

tailwind css未被应用-react

创建一个TypeScrip对象并基于来自输入对象的约束定义其类型

为什么数字是`{[key:string]:UNKNOWN;}`的有效密钥?

如何在TypeScript中将元组与泛型一起使用?

React-跨组件共享功能的最佳实践

如何通过nx找到所有受影响的项目?

const 使用条件类型时,通用类型参数不会推断为 const

具有来自其他类型的修改键名称的 TypeScript 通用类型