Typescript:如何确保对象类型中的所有键都在声明的枚举中?

时间:2020-10-29 18:42:32

标签: typescript

我有一个对象类型,该对象类型使用一个枚举中的所有键都声明为字符串:

enum MyProperties {
  PROP_A = 'propA',
  PROP_B = 'propB',
  PROP_C = 'propC'
}

type Foo {
  [value in MyProperties]: string;
}

如何在将Foo中的属性之一声明为数字的同时仍确保其所有键都在MyProperties中?

type Foo {
  propA: string;
  propB: string;
  propC: number;
}

4 个答案:

答案 0 :(得分:1)

就这么简单

export type Foo {
  [value in keyof typeof MyProperties]: string;
}

答案 1 :(得分:1)

如果您希望将特定属性键入为数字,则可以执行以下操作:

type Foo<T extends MyProperties> = {
  [value in MyProperties]: T extends value ? number : string;
}

或者您可以使用更通用的解决方案:

enum MyProperties {
  PROP_A = 'propA',
  PROP_B = 'propB',
  PROP_C = 'propC'
}

type OneOf<T extends {
    [key: string]: any;
}, R, P extends keyof T = keyof T> = P extends keyof T ? {
   [K in P]: R;
} & {
    [K in keyof Omit<T, P>]: T[K];
} : never

type Foo = OneOf<{
  [value in MyProperties]: string;
}, number>

const k: Foo = {
   propA: "",
   propB: 3,
   propC: "",
}

答案 2 :(得分:1)

决定继续使用:

enum MyProperties {
  PROP_A = 'propA',
  PROP_B = 'propB',
  PROP_C = 'propC'
}

type Foo {
  [MyProperties.PROP_A]: string;
  [MyProperties.PROP_B]: string;
  [MyProperties.PROP_C]: number;
}

希望找到一种既简单又简单的方法来做到这一点。但是,由于只有这么少的一组属性,看起来很明确。

答案 3 :(得分:0)

您要为一个对象定义一个类型,该对象的键与枚举中的每个值匹配,并且值不同(在示例中为stringnumber)。您要强制每个键都匹配适当的值,同时还要求所有键都具有某​​个值。

这可能有点令人困惑,因为我们试图在 type 而不是对象上强制键入。但是我们可以做一些事情。

  1. 我们可以按值类型将属性分为几组。由于此处我们只有两种值类型,因此我们可以将一种定义为另一种的剩余值。
type NumberProperties = MyProperties.PROP_C;

type StringProperties = Exclude<MyProperties, NumberProperties>

type Foo = {
    [K in NumberProperties]: number;
} & {
    [K in StringProperties]: string;
}

Link

  1. 我们可以使用帮助程序类型MissingKeys来检查编译时是否没有忘记任何内容。我们确实需要自己检查它,因为不会引发任何错误。
enum MyProperties {
  PROP_A = 'propA',
  PROP_B = 'propB',
  PROP_C = 'propC'
}

type Foo = {
  [MyProperties.PROP_B]: string;
  [MyProperties.PROP_C]: number;
}

type MissingKeys = Exclude<MyProperties, keyof Foo> // evaluates to MyProperties.PROP_A

Link

  1. 我的最爱。我们可以在类型中添加声明,声明必须在实现Foo的对象中设置所有缺少的属性。让我们给它一个不合逻辑的值,以便我们可以注意到Foo中缺少某些内容,并相应地调整了Foo。我喜欢这一行,因为我们得到了一个大的红色下划线,因此很明显该类型是错误的。
type DefinedFoo = {
  [MyProperties.PROP_B]: string;
  [MyProperties.PROP_C]: number;
}

type MissingKeys = Exclude<MyProperties, keyof DefinedFoo> // evaluates to MyProperties.PROP_A

type Foo = DefinedFoo & {
    [K in MissingKeys]-?: "missing property definition" 
}

const fooImplementation1: Foo = {
    [MyProperties.PROP_B]: "b",
    [MyProperties.PROP_C]: 0,
}
// gives an error: Property 'propA' is missing...

const fooImplementation2: Foo = {
    [MyProperties.PROP_A]: "a",
    [MyProperties.PROP_B]: "b",
    [MyProperties.PROP_C]: 0,
}
// gives an error: Type of computed property's value is '"a"', which is not assignable to type '"missing property definition"'

Link