为什么 Exclude 实用程序类型无法与 TypeScript 中枚举上的映射条件类型结合使用?

Why is the Exclude utility type not working as expected in combination with mapped conditional types on enums in 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;
    };
  };
};

但是 Category.OtherExclude 不起作用。如果它的父对象键的类型为 IssueType.Error,则它应该只是强制性的 属性。我在这里做错了什么?

我也想避免(如果可能的话)Nullable Types 例如:

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

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

为了清楚起见,我将 K 重命名为 ABC

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;
    };
  };
};

检查playground