Typescript 将对象键约束到枚举';s值,但不要求所有键都存在,并且对象值不被视为未定义

Typescript 将对象键约束到枚举';s值,但不要求所有键都存在,并且对象值不被视为未定义,typescript,enums,Typescript,Enums,这里有很多类似的问题,但它们没有涵盖文章末尾的检查表(尤其是“价值未定义”部分) 我有一个枚举 enum E { A = 'A', B = 'B' } 然后,我想将状态中的对象值约束为{[key in E]:string},但这需要我实例化该对象,该对象已经包含了所有enum的键。这是不允许的: const state: { [key in E]: string } = {}; 类型“{}”缺少类型“{A:字符串”中的以下属性; B:string;}”:A,B 所以我试着像这样约束它

这里有很多类似的问题,但它们没有涵盖文章末尾的检查表(尤其是“价值未定义”部分)

我有一个枚举

enum E {
  A = 'A',
  B = 'B'
}
然后,我想将状态中的对象值约束为
{[key in E]:string}
,但这需要我实例化该对象,该对象已经包含了所有enum的键。这是不允许的:

const state: { [key in E]: string } = {};
类型“{}”缺少类型“{A:字符串”中的以下属性; B:string;}”:A,B

所以我试着像这样约束它
{[key in E]?:string}
。这允许我省略枚举键,从而允许实例化空对象
{}
,并检查键值是否在枚举的范围内:

state.A = 'x'; // ok
state.C = 'y'; // gives error which is nice
但我在处理对象条目时遇到了这个问题

Object.entries(state).forEach(([key, value]) => console.log(value === undefined));
Typescript认为
value
可以是
string | undefined
类型,但这绝不是真的

仅使用字符串作为键时,该值不被视为未定义

const state: { [key: string]: string } = {};


如何将对象键约束到枚举值,而不需要它们的存在且值未定义

检查表:

state.A = 'x' // ok
state.C = 'x' // error
Object.entries(state).forEach(([key, value])=>console.log(value.charAt(0))); // ok, no Object is possibly 'undefined'.(2532) error
TLDR:我想去掉枚举E中的
断言
{
A=‘A’,
B='B'
}
O型=E型钥匙
常量状态:{[key in keyof typeof E]?:string}={};
如果要使
状态
可变,只需使用
-readonly

const state:{-readonly[key in keyof typeof E]?:string}={};
如何将对象键约束到枚举值,而不需要它们的存在且值未定义

你能提供一些伪代码吗

因为,如果key不是必需的,您将尝试获取不存在key的值,根据JS标准,您将收到
undefined

更新

enum E{
A=‘A’,
B=‘B’,
C=‘C’,
D='D'
}
//功劳归于https://stackoverflow.com/a/50375286
类型UnionToIntersection=(U扩展任何?(k:U)=>void:never)扩展(
k:我推断
)=>无效
? 我
:从不;
// //https://github.com/microsoft/TypeScript/issues/13298#issuecomment-468114901
类型UnionToOvlds=UnionToIntersection<
你有吗?(f:U)=>无效:从不
>;
类型PopUnion=UnionToOvlds扩展(a:推断a)=>void?答:从来没有;
类型IsUnion=[T]扩展了[UnionToIntersection]?假:真;
类型UnionToArray=IsUnion扩展为true
? 工会阵列
:[T,…A];
类型状态={
[P in T]:IsUnion扩展为true?状态:R
}[T]
//所有可能键的数组
类型结果=UnionToArray
//使用适当的键将并集转换为对象
类型MapPredicate=UnionToIntersection
//不允许空对象,因为值不能未定义
键入Empty={uuuu标记:'Empty'}
//遍历字符串数组
类型映射字符串<
啊,,
结果=空
>=Arr扩展[]
? []
:Arr扩展[推断H]
? 结果|映射谓词
:Arr延伸[推断头部,…推断尾部]
? 映射字符串
:只读;
//遍历字符串数组的数组
类型映射阵列<
Arr扩展了数组,
结果扩展数组=[]
>=Arr扩展[]
? []
:Arr扩展[推断H]
? […结果,MappedString]
:Arr延伸[推断头部,…推断尾部]
? Mappedaray
:只读;
键入AllPossibleValues=MappedArray[number];
常数A:AllPossibleValues={A:'A'}
常数AB:AllPossibleValue={A:A',B:B'}
常量ABC:AllPossibleValues={A:A',B:B',C:C'}
常量ABCD:AllPossibleValue={A:A',B:B',C:C',D:D'}
常量CD:AllPossibleValues={C:'C',D:'D'}
常量AD:AllPossibleValues={A:A',D:D'}
常量BD:AllPossibleValues={B'B',D'D'}
常量BE:AllPossibleValues={}//预期错误
常量QA:AllPossibleValues={A:'A',Q:'Q'}//预期错误
常量状态:AllPossibleValues={A:'A'}
const x=Object.entries(state).forEach(([key,value])=>{/*[key:string,value:string]*/
})
优点:没有断言,没有类型转换

缺点:我必须使用类似的映射UTIL,但我不知道如何重构。但它不会影响编译后的代码。另外,如果将第5个属性添加到enum,由于递归限制,上述代码将无法编译:)

所以,如果你的物体的道具少于5个,你就可以走了

TypeScript允许大约50次递归调用

如果你的obj有5个道具,你应该用
parseInt('11111',2)
31个道具创建union。我想因为我的rec
mappedaray
调用rec
MappedString
我更快地达到了这个极限

枚举E{
A=‘A’,
B='B'
}
O型=E型钥匙
常量状态:{[key in keyof typeof E]?:string}={};
如果要使
状态
可变,只需使用
-readonly

const state:{-readonly[key in keyof typeof E]?:string}={};
如何将对象键约束到枚举值,而不需要它们的存在且值未定义

你能提供一些伪代码吗

因为,如果key不是必需的,您将尝试获取不存在key的值,根据JS标准,您将收到
undefined

更新

enum E{
A=‘A’,
B=‘B’,
C=‘C’,
D='D'
}
//功劳归于https://stackoverflow.com/a/50375286
类型UnionToIntersection=(U扩展任何?(k:U)=>void:never)扩展(
k:我推断
)=>无效
? 我
:从不;
// //https://github.com/microsoft/TypeScript/issues/13298#issuecomment-468114901
类型UnionToOvlds=UnionToIntersection<
你有吗?(f:U)=>无效:从不
>;
类型PopUnion=UnionToOvlds扩展(a:推断a)=>void?答:从来没有;
类型IsUnion=[T]扩展了[UnionToIntersection]?假:真;
类型UnionToArray=IsUnion扩展为true
? 工会阵列
:[T,…A];
类型状态={
[P in T]:IsUnion扩展了true?状态
const state: { [key in E]?: string } = {};
state.A = undefined;
const isDefinedValue = <T,>(tuple: [string, T | undefined]): tuple is [string, Exclude<T, undefined>] => {
  return tuple[1] !== undefined;
}
Object.entries(state)
  .filter(isDefinedValue)
  .forEach(([key, value])=>console.log(value.charAt(0)));  // value is `string`