函数props与泛型的 TypeScript 组合

IT技术 reactjs typescript typescript-generics react-typescript
2022-07-15 01:11:09

这种类型的重点是允许用户传入data, color, hasColordata, info, hasInfo不是任何其他组合。

type Props = {
  data: string;
} & (
  | {
      info?: string;
      hasInfo?: boolean;
      color?: never;
      hasColor?: never;
    }
  | {
      info?: never;
      hasInfo?: never;
      color?: string;
      hasColor?: boolean;
    }
);


function foo(props: Props) {
  console.log("bar");
}

foo({ data: "hello", info: "hello", hasInfo: true }); <----- TypeScript is happy
foo({ data: "hello", info: "hello", hasColor: true }); <----- TypeScript gives Error

有没有更简洁的方法来使用泛型来实现这种行为?

我试过这个,但看起来我以某种方式搞乱了三元的逻辑:

type Info = { info: string; hasInfo: boolean };
type Color = { color: string; hasColor: boolean };
type Data = { data: string };

function foo<T>(
  props: keyof T extends keyof Info ? Data & Info : Data & Color
) {
  console.log("bar");
}

foo({ data: "hello", color: "hello", hasColor: true }); <----TypeScript gives Error

第一种方法有效,但看起来很丑。

2个回答

使用您当前的定义,TypeScript 无法推断类型参数T,因此推断为unknown调用函数时。因此,keyof Tis justnever并且条件总是解析为 false 分支。

为了解决这个问题,我们可以将条件的结果与 相交T

function foo<T>(
  props: keyof Info extends keyof T 
    ? Data & Info & T 
    : Data & Color & T
) {
  console.log("bar");
}

另请注意,我们必须切换keyof T extends keyof Infokeyof Info extends keyof T. keyof T将是更大的联合,因此不能扩展keyof Info


操场

玩了一圈后,我找到了另一个可靠的解决方案:

type Info = { info?: string; hasInfo?: boolean };
type Color = { color?: string; hasColor?: boolean };
type Data = { data: string };

function foo<T>(
  props: keyof Info extends keyof T
    ? Exclude<T, Color> & Data & Info
    : Exclude<T, Info> & Data & Color
) {
  console.log('bar');
}

操场