英文:
What type should I declare for my data (using TypeScript)?
问题
您可以使用 TypeScript 中的映射类型来声明结果类型并实现您的需求。以下是一个示例:
type ResultType = {
[K in SecondEnum]: {
[P in FirstEnum]?: string;
};
};
const getSecondEnumValuesBasedOnMap: ResultType = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: 'some value',
},
[SecondEnum.secondEnumKey2]: {
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
[SecondEnum.secondEnumKey3]: {
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
};
这个 ResultType
类型将确保您的 getSecondEnumValuesBasedOnMap
符合指定的结构。如果您更改了映射或结果不符合所需的结构,TypeScript 将会发出相应的错误提示,帮助您保持类型一致性。
英文:
This is part of my TypeScript code.
enum FirstEnum {
firstEnumKey1 = 'firstEnumKey1',
firstEnumKey2 = 'firstEnumKey2',
firstEnumKey3 = 'firstEnumKey3',
firstEnumKey4 = 'firstEnumKey4',
}
enum SecondEnum {
secondEnumKey1 = 'secondEnumKey1',
secondEnumKey2 = 'secondEnumKey2',
secondEnumKey3 = 'secondEnumKey3',
}
// map first enum to second enum
const map: {[i in FirstEnum]: SecondEnum[] } = {
'firstEnumKey1': [SecondEnum.secondEnumKey1],
'firstEnumKey2': [],
'firstEnumKey3': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
'firstEnumKey4': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
};
I have two enums and a const which map them. I'm using the map to define some data that for each SecondEnum has an object. The object keys should be map keys which had that specific SecondEnum value in their array.
So now my result should be like this.
const getSecondEnumValuesBasedOnMap = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: 'some value',
},
[SecondEnum.secondEnumKey2]: {
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
[SecondEnum.secondEnumKey3]: {
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
}
If I change my map my data should change based on it. for example if I add SecondEnum.secondEnumKey2
to FirstEnum.firstEnumKey2
my data should change like this:
// map first enum to second enum
const map: {[i in FirstEnum]: SecondEnum[] } = {
'firstEnumKey1': [SecondEnum.secondEnumKey1],
'firstEnumKey2': [SecondEnum.secondEnumKey2],
'firstEnumKey3': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
'firstEnumKey4': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
};
const getSecondEnumValuesBasedOnMap = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: 'some value',
},
[SecondEnum.secondEnumKey2]: {
[FirstEnum.firstEnumKey2]: 'some value',
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
[SecondEnum.secondEnumKey3]: {
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
}
I want to declare a type for my result so when I changed my map I get errors to update my result but I'm kind of new to typescript and I don't know how.
答案1
得分: 3
以下是您要翻译的内容:
首先,我们需要更改 map
的类型,因为它当前没有为 SecondEnum
提供文字值,我们无法确定使用了哪些确切的值。
为了防止编译器扩展类型,我们将使用 const assertion,并且为了保持类型安全性,我们将使用 satisfies 运算符:
const map = {
firstEnumKey1: [SecondEnum.secondEnumKey1],
firstEnumKey2: [SecondEnum.secondEnumKey2],
firstEnumKey3: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
firstEnumKey4: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
} as const satisfies {[K in FirstEnum]: readonly SecondEnum[]};
// 类型 EnumMap = {
// readonly firstEnumKey1: readonly [SecondEnum.secondEnumKey1];
// readonly firstEnumKey2: readonly [SecondEnum.secondEnumKey2];
// readonly firstEnumKey3: readonly [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3];
// readonly firstEnumKey4: readonly [...];
// }
type EnumMap = typeof map;
接下来,让我们定义一个类型,它接受一个由 SecondEnum
约束的泛型参数,并查找在 map
中具有此特定项的 FirstEnum
成员。我们将使用 mapped types 遍历 map
,并使用 key remapping 来排除不适合的成员,并最终返回具有此第二枚举值的 map
键:
type FindValue<T extends SecondEnum> = keyof {
[K in keyof EnumMap as T extends EnumMap[K][number] ? K : never]:EnumMap[K]
}
让我们为 getSecondEnumValuesBasedOnMap
定义一个类型。我们将再次使用 mapped types
和 key remapping
来排除根本未使用的第二枚举成员:
{
[K in SecondEnum as [FindValue<K>] extends [never] ? never : K]: {
[P in FindValue<K>]: string
}
}
请注意,在 [FindValue<K>] extends [never]
中的 []
非常重要,因为 never
是一个空集,并且是每个联合类型的超类型,为了确保此检查按预期工作,我们使用 []
防止编译器分发类型。
在值中,我们正在遍历 FindValue<K>
的结果,该结果返回了第二个枚举用于的键,并分配了类型 string
的值:
const getSecondEnumValuesBasedOnMap:{
[K in SecondEnum as [FindValue<K>] extends [never] ? never : K]: {
[P in FindValue<K>]: string
}
} = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: 'some value',
},
[SecondEnum.secondEnumKey2]: {
[FirstEnum.firstEnumKey2]: 'some value',
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
[SecondEnum.secondEnumKey3]: {
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
};
英文:
First of all, we need to change the type of the map
, since it is currently not having literal values for the SecondEnum
and we won't be able to determine which exact values are used.
To prevent the compiler from widening the types we will use const assertion and to maintain type safety we will use satisfies operator:
const map = {
firstEnumKey1: [SecondEnum.secondEnumKey1],
firstEnumKey2: [SecondEnum.secondEnumKey2],
firstEnumKey3: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
firstEnumKey4: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
} as const satisfies {[K in FirstEnum]: readonly SecondEnum[]};
// type EnumMap = {
// readonly firstEnumKey1: readonly [SecondEnum.secondEnumKey1];
// readonly firstEnumKey2: readonly [SecondEnum.secondEnumKey2];
// readonly firstEnumKey3: readonly [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3];
// readonly firstEnumKey4: readonly [...];
// }
type EnumMap = typeof map;
Next, let's define a type that accepts a generic parameter constrained by SecondEnum
and find the members of FirstEnum
that have this specific item in the map
. We are going to use mapped types to map through the map
and key remapping to exclude those that are not suitable, and at the end return the keys of the map
that have this second enum in them:
type FindValue<T extends SecondEnum> = keyof {
[K in keyof EnumMap as T extends EnumMap[K][number] ? K : never]:EnumMap[K]
}
Let's define a type for the getSecondEnumValuesBasedOnMap
. We will need to use mapped types
and key remapping
again to exclude those second enum members that are not used at all:
{
[K in SecondEnum as [FindValue<K>] extends [never] ? never : K]: {
[P in FindValue<K>]: string
}
}
Note that []
are really important in the [FindValue<K>] extends [never]
, since never
is an empty set and is a supertype for every union and to make sure that this check works as expected we prevent the compiler from distributing the types using the []
.
And in the values, we are mapping through the result of FindValue<K>
which returns as the keys where the second enum is used and assigns a value of type string
:
const getSecondEnumValuesBasedOnMap:{
[K in SecondEnum as [FindValue<K>] extends [never] ? never : K]: {
[P in FindValue<K>]: string
}
} = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: 'some value',
},
[SecondEnum.secondEnumKey2]: {
[FirstEnum.firstEnumKey2]: 'some value',
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
[SecondEnum.secondEnumKey3]: {
[FirstEnum.firstEnumKey3]: 'some value',
[FirstEnum.firstEnumKey4]: 'some value',
},
};
答案2
得分: 0
以下是您要翻译的内容:
声明类型如下:
type GetSecondEnumValuesBasedOnMap = {
[K in SecondEnum]: Partial<{ [L in FirstEnum]: string }>
}
然后使用如下:
const getSecondEnumValuesBasedOnMap: GetSecondEnumValuesBasedOnMap = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: 'some value',
}
}
英文:
declare type like this:
type GetSecondEnumValuesBasedOnMap = {
[K in SecondEnum]: Partial<{ [L in FirstEnum]: string }>
}
then use like this:
const getSecondEnumValuesBasedOnMap: GetSecondEnumValuesBasedOnMap = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: 'some value',
}
答案3
得分: 0
我认为最好将地图声明为一种类型,而不是一个常数(假设您在计算中没有使用它)。如果您这样做,还可以反转键和值以使映射更容易,您可以像这样声明所有类型:
type EnumTypeMap = {
[SecondEnum.secondEnumKey1]: FirstEnum.firstEnumKey1;
[SecondEnum.secondEnumKey2]: FirstEnum.firstEnumKey3 | FirstEnum.firstEnumKey4;
[SecondEnum.secondEnumKey3]: FirstEnum.firstEnumKey3 | FirstEnum.firstEnumKey4;
};
type ValueEnumTypeMap = {
[key in keyof EnumTypeMap]: {
// Unfortunately I wasn't sure how else to set the type of the index as `EnumTypeMap[key]`
// (loops through a single key and then changes the type to the type we need)
[innerKey in keyof { key: key } as EnumTypeMap[key]]: string;
};
};
const getSecondEnumValuesBasedOnMap: ValueEnumTypeMap = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: "some value",
},
[SecondEnum.secondEnumKey2]: {
[FirstEnum.firstEnumKey2]: "some value", // Error
[FirstEnum.firstEnumKey3]: "some value",
[FirstEnum.firstEnumKey4]: "some value",
},
[SecondEnum.secondEnumKey3]: {
[FirstEnum.firstEnumKey3]: "some value",
[FirstEnum.firstEnumKey4]: "some value",
},
};
英文:
I think it would be better to declare the map as a type rather than a constant (assuming you do not also need to use it in your calculations).<br/> If you do that and also invert the keys and values to make the mapping easier, you can declare all the types like this:
type EnumTypeMap = {
[SecondEnum.secondEnumKey1]: FirstEnum.firstEnumKey1;
[SecondEnum.secondEnumKey2]: FirstEnum.firstEnumKey3 | FirstEnum.firstEnumKey4;
[SecondEnum.secondEnumKey3]: FirstEnum.firstEnumKey3 | FirstEnum.firstEnumKey4;
};
type ValueEnumTypeMap = {
[key in keyof EnumTypeMap]: {
// Unfortunately I wasn't sure how else to set the type of the index as `EnumTypeMap[key]`
// (loops through a single key and then changes the type to the type we need)
[innerKey in keyof { key: key } as EnumTypeMap[key]]: string;
};
};
const getSecondEnumValuesBasedOnMap: ValueEnumTypeMap = {
[SecondEnum.secondEnumKey1]: {
[FirstEnum.firstEnumKey1]: "some value",
},
[SecondEnum.secondEnumKey2]: {
[FirstEnum.firstEnumKey2]: "some value", // Error
[FirstEnum.firstEnumKey3]: "some value",
[FirstEnum.firstEnumKey4]: "some value",
},
[SecondEnum.secondEnumKey3]: {
[FirstEnum.firstEnumKey3]: "some value",
[FirstEnum.firstEnumKey4]: "some value",
},
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论