TypeScript:从其他字符串文字联合类型限制区分联合中的鉴别器

TypeScript: Limit discriminator in discriminated union from other string literal union type

我有一个非常基本的判别联合,但对于判别器,我只想允许来自另一个字符串文字联合类型的特定值。这将使向受歧视的联合添加新的联合“案例”变得更加容易。

这是一个字符串文字联合,它描述了该类型允许的“值”:

type AllowedType = "typeForNumber" | "typeForBoolean"

然后,我描述数据的类型使用该字符串文字联合:

type Data = {
  type: AllowedType,
  value: number | boolean
}

根据我的示例,有两个选项,可以根据 type 字段为 value 指定更具体的类型。我不使用这些选项,它们只是用于演示目的:

// Option 1 - "value" is a "number"
type DataOption1 = {
  type: "typeForNumber",
  value: number
}
// Option 2 - "value" is a "boolean"
type DataOption2 = {
  type: "typeForBoolean",
  value: boolean
}

所以我真正想做的是 Data 的可区分联合,因为这样我可以为其 value 字段提供更具体的类型:

type Data =
  | {
      type: "typeForNumber"
      value: number
    }
  | {
      type: "typeForBoolean"
      value: boolean
    }

当你使用类型时,一切正常:

const myData: Data = {
  type: "typeForNumber",
  // this creates an error, should be a `number`
  value: "some string"
}

我的问题是:如何确保我的 Data 类型中的 type 字段只能是 AllowedType 的选项之一?

以后AllowedType会有更多的选择,所以我想用它们限制可能的联合类型。

可以像这样更改添加另一个联合到 Data 类型,没有任何错误:

type Data =
  | {
      type: "typeForNumber"
      value: number
    }
  | {
      type: "typeForBoolean"
      value: boolean
    }
  | {
      type: "someOtherType"
      value: string
    }

不应允许这个新联合(与 type: "someOtherType")。

是否可以从其他字符串文字联合类型 (AllowedType) 中限制此已区分联合 (Data) 中的鉴别器 (type)?

我尝试对交集使用包装器,但联合会忽略(覆盖?)type 类型:

type AllowedType = "typeForNumber" | "typeForBoolean"

type DataWrapper = {
  type: AllowedType
  value: number | boolean
}

type Data = DataWrapper &
  (
    | {
        type: "typeForNumber"
        value: number
      }
    | {
        type: "typeForBoolean"
        value: boolean
      }
  )

如果我理解正确,问题是 DataAllowedType 可能不同步。如果这是问题所在,您可以扭转局面,根据 Data 定义 AllowedType,如下所示:

type Data =
  | {
      type: "typeForNumber"
      value: number
    }
  | {
      type: "typeForBoolean"
      value: boolean
    };

type AllowedType = Data["type"];

Playground link

然后,添加到 Data 会自动添加到 AllowedType


在评论中,您曾说过您正在努力防止 Data 联盟的 type 中的拼写错误:

In my case, the Data type represents dynamic data coming from another source, so I want to be sure that there are e.g. no typos in the type values (like typeForNumber). That's why I'm so keen to find a solution to limit the type to specific values. Turning it around doesn't help in my case.

这似乎对此有所帮助:

type CheckData<DataType extends {type: AllowedType}> =
    Exclude<DataType["type"], AllowedType> extends never
        ? DataType
        : never;

然后这个有效:

type Data = CheckData<
    | {
        type: "typeForNumber"
        value: number
    }
    | {
        type: "typeForBoolean"
        value: boolean
    }>;

但这不是:

type Data2 = CheckData<
    | {
        type: "typeForNumber"
        value: number
    }
    | {
        type: "typeForBoolean"
        value: boolean
    }
    | {
        type: "typeForSomethingElse"
        value: boolean
    }>;

Playground link

不过,它不会捕捉到 所有 错别字。它允许两种类型都使用相同的 type 值。