【问题标题】:Union of types was reduced to 'never' breaks typing: Type was reduced to 'never' because property has conflicting types in some constituents类型的联合被简化为“从不”打断打字:类型被简化为“从不”,因为属性在某些成分中具有冲突的类型
【发布时间】:2021-06-25 15:43:18
【问题描述】:

我有一个从基本接口扩展而来的类型集合:

interface BaseType {
  id: number;
  titleText: string;
}

export enum ComponentType {
  AUDIO = 'type_audio',
  ARTICLE = 'type_article',
  BASIC = 'type_basic',
  DOWNLOAD = 'type_download',
  LINK = 'type_link',
  QUOTE = 'type_quote',
  VIDEO = 'type_video',
}

export interface BasicComponent extends BaseType {
  type: ComponentType.BASIC;
}

export interface QuoteComponent extends BaseType {
  type: ComponentType.QUOTE;
  subtitle?: string;
}

export interface LinkComponent extends BaseType {
  type: ComponentType.LINK | ComponentType.ARTICLE;
  subtitle?: string;
}


export interface DownloadComponent extends BaseType {
  type: ComponentType.DOWNLOAD;
}

export interface AudioComponent extends BaseType {
  type: ComponentType.AUDIO;
  mediaType: MediaType.AUDIO;
  mediaRef: Reference;
  configRef: Reference;
}

export interface VideoComponent extends BaseType {
  type: ComponentType.VIDEO;
  mediaType: MediaType.VIDEO;
  mediaRef: Reference;
  configRef: Reference;
}

但是,当我创建一个可以是这些组件类型中的任何一种的类型,并使用 switch case 将它们分配给 React 组件时,我得到了一个错误。

export type Component =
  | BasicComponent
  | AudioComponent
  | DownloadComponent
  | LinkComponent
  | VideoComponent
  | QuoteComponent;

  const getChild = () => {
    switch (props.type) {
      case ComponentType.AUDIO:
        return AudioComponent;
      case ComponentType.DOWNLOAD:
        return DownloadComponent;
      case ComponentType.ARTICLE:
      case ComponentType.LINK:
        return LinkComponent;
      case ComponentType.QUOTE:
        return QuoteComponent;
      case ComponentType.VIDEO:
        return VideoComponent;
      case ComponentType.BASIC:
        return BasicComponent;
    }
  };

  const Component = getChild();

  return <Component {...props} />;
  //           ^^^
  // The intersection 'IntrinsicAttributes & AudioTeaser & { children?: ReactNode; } &
  // DownloadTeaser & LinkTeaser & QuoteTeaser & VideoTeaser & BasicTeaser' was reduced
  // to 'never' because property 'type' has conflicting types in some constituents.

  // Type props is not assignable to type 'never'.

【问题讨论】:

  • 请分享可重现的例子
  • 我看到的最大问题是你有接口(只描述一个类型)并且你将它们用作getChild 中的值(返回BasicComponent)。您需要了解 typescript 接口/类型在运行时不存在。
  • @AndreiTătar getChild 是一个组件函数,其中有 prop 值。我将更新问题以使这一点更清楚。
  • @CAJE 可能最简单的方法是在 stackblitz 上添加最少的可重现代码。

标签: reactjs typescript


【解决方案1】:

这需要类似 corelated 类型,其中 typescript 可以知道 Componentprops 的类型是 corelated。目前不存在。

发生的事情是Component 最终成为所有可能组件的联合。由于Component 可以是任何一个有效组件,因此只有使用满足所有可能组件道具(因此是所有可能道具的交集)的道具来创建此组件才是安全的。由于 props 是互斥的,因此您最终会在此交集的某处得到 never(即没有可能值的类型)。

最简单的解决方案是使用类型断言将组件的并集转换为接受道具的组件,该道具是所有可能道具的并集。现在这通常并不安全,但在这种情况下,我们告诉 typescript 我们更了解:

    const Component = getChild() as React.FC<Component>;

    return <Component {...props} />;

Playground Link

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 2020-10-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多