首页 > 解决方案 > 为什么 Exclude 实用程序类型与 TypeScript 中枚举上的映射条件类型结合使用时不能按预期工作?

问题描述

只是为了提供一点上下文:我正在构建一个非常复杂的表单,其中包含取决于先前输入中选择的条件所需值。

因此,我制作了以下对象来说明是否需要输入:

enum IssueType {
  Error = "Error",
  Advice = "Advice",
}

enum Category {
  Software = "Software",
  Hardware = "Hardware",
  Other = "Other",
}

const inputNames = {
  issueType: "issueType",
  concerning: "concerning",
  serialNumber: "serialNumber",
  errorCode: "errorCode",
} as const;

const conditions: Conditions = {
  [IssueType.Error]: {
   ~~~~~~~~~~~~~~~> Property 'Other' is missing in type ...
    [Category.Software]: {
      [inputNames.concerning]: true,
      [inputNames.serialNumber]: true,
      [inputNames.errorCode]: true,
    },
    [Category.Hardware]: {
      [inputNames.concerning]: true,
      [inputNames.serialNumber]: true,
      [inputNames.errorCode]: true,
    }
  },
  [IssueType.Advice]: {
    [Category.Software]: {
      [inputNames.concerning]: true,
      [inputNames.serialNumber]: true,
      [inputNames.errorCode]: true,
    },
    [Category.Hardware]: {
      [inputNames.concerning]: true,
      [inputNames.serialNumber]: true,
      [inputNames.errorCode]: true,
    },
    [Category.Other]: {
      [inputNames.concerning]: true,
      [inputNames.serialNumber]: true,
      [inputNames.errorCode]: true,
    }
  }
};

现在我的问题是类型(Conditions在上面的片段中)是conditions什么样的。我试过这个:

type Conditions = {
  [K in IssueType]: {
    [K in IssueType extends IssueType.Error
      ? Exclude<Category, Category.Other>
      : Category]: {
      [K in Exclude<
        keyof typeof inputNames,
        typeof inputNames.issueType
      >]: boolean;
    };
  };
};

但是ExcludeofCategory.Other不起作用。只有当它的父对象键是 type 时,它​​才应该是一个强制属性IssueType.Error。我在这里做错了什么?

我也想避免(如果可能的话)像这样的可空类型:

type Conditions = {
  [K in IssueType]: {
    [K in Category]?: {
      [K in Exclude<
        keyof typeof inputNames,
        typeof inputNames.issueType
      >]: boolean;
    };
  };
};

标签: typescripttypesenumsconditional-typesmapped-types

解决方案


在对象的第二层,您应该引用K(从上一层)而不是IssueType. 为此,您不能K为所有级别命名密钥类型。

这是我KA,BC为清楚起见重命名的地方:

type Conditions = {
  [A in IssueType]: {
    [B in A extends IssueType.Error
      ? Exclude<Category, Category.Other>
      : Category]: {
      [C in Exclude<
        keyof typeof inputNames,
        typeof inputNames.issueType
      >]: boolean;
    };
  };
};

检查操场


推荐阅读