用于道具的 TypeScript 条件类型

Posted

技术标签:

【中文标题】用于道具的 TypeScript 条件类型【英文标题】:TypeScript conditional types for props 【发布时间】:2021-06-29 05:09:12 【问题描述】:

我有一个组件可以处于两种不同的状态,编辑模式和查看模式。为了适应这一点,我有一个联合类型来完成这项工作,但我仍然在我的组件的 args 中收到 TypeScript 抱怨:

type View = 
    isEditing: false;
    viewHandler: () => void;
    someOtherProp: any // this is unique to view mode
;

type Edit = 
    isEditing: true;
    editHandler: (id: string) => void;
;

export type MyProps = View | Edit;

然后在这里抱怨:

const Item: React.FC<MyProps> = (
    isEditing = false,
    editHandler,
    ~~~~~~~~~~~
) => 

Property 'editHandler' does not exist on type 'PropsWithChildren&lt;MyProps&gt;'.

我错过了什么?

【问题讨论】:

所以,如果isEditingfalse,你希望它是View,如果没有提供isEditing,或者true 它是Edit,同时如果isEditing 未提供(Edit 模式),您将其默认为 falseView 模式)。您能否举例说明您打算如何使用该组件? 在编辑模式下,它真的不应该是可选的,这是一个疏忽,所以组件要么处于编辑模式,要么处于查看模式,根据它所处的模式,我们渲染不同的子组件,我们将处理程序传递到。我们将处理程序一直沿树向下传递,以在页面级别管理我们的状态并将逻辑保持在一个位置。 也许type View = isEditing?: false;editHandler: undefined;type Edit = isEditing: true;editHandler: (id: string) =&gt; void;; 对你有用?或者最好还是做 2 个组件 不,已经尝试过了,然后我在调用处理程序时得到Cannot invoke an object which is possibly 'undefined'. 使用 ! 让 TS 知道某些东西不是 null /undefined editHandler!() 【参考方案1】:

我认为它也应该出现在您的视图类型中,如下所示:

type View = 
  isEditing: false;
  editHandler?:(id: string) => void;
;

type Edit = 
  isEditing?: true;
  editHandler: (id: string) => void;
;

【讨论】:

这是一个非常简化的虚拟代码,有多个处理程序和其他传递的道具,所以在这两种情况下添加所有处理程序会增加很多冗余并且不是很安全,那会意味着 ViewMode 仍然能够让 Edit 处理程序通过,反之亦然。 是的,我明白...但是正如您所写的export type MyProps = View | Edit 然后查看和编辑应该有您想要在React.FC&lt;MyProps&gt; = ( isEditing = false, editHandler ) 中拥有的键。 刚刚尝试这种方法看看是否可行,现在我实际上得到了 Cannot invoke an object which is possibly 'undefined'. 我调用该函数的位置【参考方案2】:

所以我现在使用的解决方案是添加它并输入为never

type View = 
    isEditing: false;
    viewHandler: () => void;
    editHandler?: never;
;

type Edit = 
    isEditing: true;
    editHandler: (id: string) => void;
    viewHandler?: never;
;

export type MyProps = View | Edit;

在事件处理程序被调用或传递时,我使用! 来确保 TypeScript 不能取消定义。 感谢 Nadia 在上面的评论中为我指明了正确的方向!

【讨论】:

以上是关于用于道具的 TypeScript 条件类型的主要内容,如果未能解决你的问题,请参考以下文章

Typescript 和 React:使用 React.Component 和条件类型化道具时类型推断失败

使用 TypeScript 反应道具类型 - 如何拥有函数类型?

Typescript + Svelte - 如何添加类型以传播组件道具

收到错误的`Type'{theme:Theme; }'在尝试将其作为道具传递给App组件时无法分配给类型`

使用多种道具类型反应 Typescript 组件

Vue 在编译时使用 Typescript 类型检查道具