在打字稿中构建映射的独占类型

Building mapped exclusive type in typescript

我有以下类型(简体):

type ValueRepresents = {
    boolean: true
    number?: false
    other?: false
} |
{
    boolean?: false
    number: true
    other?: false
} |
{
    boolean?: false
    number?: false
    other: true
}

我的实际类型有更多可能的键。有没有一种方法可以从可能的键列表中生成这种类型,以使其仅在一个键的值设置为 true 时有效?类似于:

type ValueTypes = "boolean" | "number" | "other"
type ValueRepresents <T extends ValueTypes> = {
    [k in ValueTypes]: k extends T ? true : false
}
const a: ValueRepresents<"boolean"> = {
    boolean: true,
    number: false,
    other: false,
}

但我的目标是能够使用:

// should pass
const a: ValueRepresents = { boolean: true }

// should pass
const a2: ValueRepresents = {
    boolean: true,
    number: false,
}

// should error
const a3: ValueRepresents = {
    boolean: true,
    number: true,
}

// should error
const a4: ValueRepresents = {}

我也试过 但还没有成功:

type ValueRepresents <T extends ValueTypes> = {
    [k in Exclude<T, ValueTypes>]?: false
} & { [k in T]: true }

您可以尝试创建这样的联合类型

type ValueTypes = "boolean" | "number" | "other"

type ValueRepresents = ({
    [K in ValueTypes]: Partial<Record<Exclude<ValueTypes, K>, false>> & Record<K, true>
})[ValueTypes]

TypeScript Playground


TL;DR

我认为这个表达式没有特定的名称。我在 the docs in Advanced Types 中看到过类似的示例,但我会尝试解释它是如何工作的。

type ValueRepresents = {
    [K in ValueTypes]: Partial<Record<Exclude<ValueTypes, K>, false>> & Record<K, true>
}

创建的类型等效于:

type ValueRepresents = {
  boolean: {
    boolean: true;
    number?: false;
    other?: false;
  };
  number: {
    boolean?: false;
    number: true;
    other?: false;
  };
  other: {
    boolean?: false;
    number?: true;
    other: true;
  };
};

并通过在方括号 [ValueTypes] 中添加联合类型,它提取了另一个联合类型中的那些(所有)键的值,等同于:

type ValueRepresents =
  | {
      boolean: true;
      number?: false;
      other?: false;
    }
  | {
      boolean?: false;
      number: true;
      other?: false;
    }
  | {
      boolean?: false;
      number?: true;
      other: true;
    };