简体   繁体   English

强制 object 包含枚举的所有键,并且仍然对其值进行类型推断

[英]Enforce object to contain all keys of an enum and still have type inference for it's values

I have an object and I want to enforce it to contain all keys of an Enum, and I also want the type of it's values to be inferred.我有一个 object 并且我想强制它包含枚举的所有键,并且我还希望推断它的值的类型。 So if I do this:所以如果我这样做:

enum RequiredKeys {
    A = 'a',
    B = 'b'
}
const objectThatShouldContainAllRequiredKeys = {
    [RequiredKeys.A]: (id: string) => {}
};
// Argument of type '123' is not assignable to parameter of type 'string'
// Which is great, that's exactly what I want. 
objectThatShouldContainAllRequiredKeys[RequiredKeys.A](123);

But now, I tried enforcing the object keys and every solution I try breaks the type inference.但是现在,我尝试强制执行 object 键,并且我尝试的每个解决方案都会破坏类型推断。 For example:例如:

enum RequiredKeys {
    A = 'a',
    B = 'b'
}
// Property 'b' is missing in type '{ a: (id: string) => void; }' but required in type 'Record<RequiredKeys, Function>'.
// Which is great, that's exactly what I want
const objectThatShouldContainAllRequiredKeys: Record<RequiredKeys, Function> = {
    [RequiredKeys.A]: (id: string) => {}
};
// No error here, which is less great...
objectThatShouldContainAllRequiredKeys[RequiredKeys.A](123);

Any idea how I can enjoy both worlds?知道如何享受这两个世界吗? Have the object enforce all keys from the enum and infer the object values? object 是否强制执行枚举中的所有键并推断 object 值? Thanks!!谢谢!!

You can create identity function with type parameter constrained to have required keys, so typescript will validate the passed object keys and will infer its values' types:您可以创建身份 function 并将类型参数限制为具有必需的键,因此 typescript 将验证传递的 object 键并推断其值的类型:

const createWithRequiredKeys = <T extends Record<RequiredKeys, unknown>>(obj: T) => obj;

const withRequiredKeys = createWithRequiredKeys({
    [RequiredKeys.A]: (id: string) => {},
    [RequiredKeys.B]: 'foo',
}); 

// withRequiredKeys is { a: (id: string) => void; b: string; }

withRequiredKeys[RequiredKeys.A](123); // 'number' is not assignable to parameter of type 'string'

Playground 操场

Fast solution: ( SECOND UPDATE )快速解决方案:(第二次更新

enum RequiredKeys {
  A = 'a',
  B = 'b'
}

type Mapped = {
  [RequiredKeys.A]: (id: string) => any,
  [RequiredKeys.B]: (id: number) => any
}

// Property 'b' is missing in type '{ a: (id: string) => void; }' but required in type 'Record<RequiredKeys, Function>'.
// Which is great, that's exactly what I want
const objectThatShouldContainAllRequiredKeys: Mapped = {
  [RequiredKeys.A]: (id: string) => { },
  [RequiredKeys.B]: (id: number) => { }
}
// No error here, which is less great...
const result = objectThatShouldContainAllRequiredKeys[RequiredKeys.A]('ok'); // ok
const result2 = objectThatShouldContainAllRequiredKeys[RequiredKeys.B](1); // ok

const result3 = objectThatShouldContainAllRequiredKeys[RequiredKeys.B]('1'); // error
const result4 = objectThatShouldContainAllRequiredKeys[RequiredKeys.A](2); // error

If you want more generic solution, you can take a look on this answer如果你想要更通用的解决方案,你可以看看这个答案

Please keep in mind, that in case of more generic solution, you should create a type map for enum and function types请记住,在更通用的解决方案的情况下,您应该为 enum 和 function 类型创建类型 map

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM