React 根据 属性 值使用不同的接口

React use different interface in dependent on property value

我有 3 种不同类型的物品,我有它们的接口

interface TypeA{
  name: string;
}

interface TypeB{
 count: number;
}

interface TypeC{
 date: Date;
}

此项目应呈现在项目列表中(在列表中,所有项目都来自同一类型)。根据项目的类型,调用不同的方法,这将呈现不同的布局。

export const ListItem: React.FC<ListItemProps> = (props) => {
  let item = null;
  switch (props.type) {
    case "A":
      item = renderTypeA(props);
      break;
    case "B":
      item = renderTypeB(props);
      break;
    case "C":
      item = renderTypeC(props);
      break;
  }
  return item;
};

该方法应该只接受所需类型的项目。

const renderTypeA = (props: TypeAProps) => {
  {...}
};

问题是我无法让 Typescript 识别类型的所有属性,也无法自动完成相应的类型。

我也尝试过联合类型“ListItemTypes”,

type ListItemTypes = TypeA | TypeB | TypeC
export const ListItem: React.FC<ListItemTypes> = (props) => {
...
};

但是当我随后尝试包含 ListItem 时,我总是收到缺少属性的错误消息。

<ListItem {...item /> <--- is telling me that properties are missing 

有谁知道我该如何解决这个问题?

Example

下面是可区分联合用法的最小示例:

interface TypeA {
  type: "A";
  name: string;
}

interface TypeB {
  type:"B";
  count: number;
}

export const ListItem = (props: TypeA | TypeB) => {
  let item = null;
  switch (props.type) {
    case "A":
      item = renderTypeA(props); // TS know this must be TypeA in this block
      break;
    case "B":
      item = renderTypeB(props);
      break;
  }
  return item;
};

const renderTypeA = (props: TypeA) => {
  props.name; // No error
};

const renderTypeB = (props: TypeB) => {
  props.name; // Error
};

// Update:
const renderItem = () => {
  const sampleData: Array<ListItemTypes> = [
    {
      type: "A",
      count: 12, // This doesn't follow your ListItemTypes shape
    },
  ];
  // ListItem requires an object, not a list of objects
  return sampleData.map(sd => <ListItem {...sd} />);
};

我检查了你的代码,它正在抛出错误,因为你正在将一个数组解构到你的组件中。 在你的代码中


const renderItem = () => {
  const sampleData = [
    {
      type: "A",
      count: 12,
    },
  ];
  // incorrectly destructuring sampleData here
  return <ListItem {...sampleData} />;
};

你应该可以用这个来达到预期的结果:

const renderItemA = () => {
  const sampleData = {
    type: "A" as const, // notice const assertion here
    name: "name"
  };
  return <ListItem {...sampleData} />;
};

因为您将 type 定义为文字类型,所以您需要 const assertion 以便

no literal types in that expression should be widened (e.g. no going from "hello" to string)

Playground link