英文:
Enum as generic param, enforce secondary type
问题
以下是您提供的代码的翻译部分:
// 定义主要图片类型的枚举
export enum PrimaryImageType {
Artnum = "ARTNUM",
RMA = "RMA",
}
// 为主要图片类型定义次要图片类型的记录
export const SecondaryImageTypes: Record<PrimaryImageType, string[]> = {
[PrimaryImageType.Artnum]: [
"LDA_OVP",
"LDA_PALETTE",
"LDA_LABEL",
"LDA_VERPACKHINWEIS",
"LDA_MASTERKARTON",
],
RMA: [
],
};
// 定义次要图片类型的类型
export type SecondaryType<P extends PrimaryImageType> = typeof SecondaryImageTypes[P][number];
// Test 类型现在被推断为 string,我希望它是 "LDA_OVP" | "LDA_PALETTE" | "LDA_LABEL" | "LDA_VERPACKHINWEIS" | "LDA_MASTERKARTON"
type Test = SecondaryType<PrimaryImageType.Artnum>;
// 定义图像接口,使用主要图片类型
export interface Image<P extends PrimaryImageType> {
id: number,
imageType: P,
typeID: string,
secondaryType: SecondaryType<P>,
}
// TypeScript 应该强制执行次要类型的联合:
const testImg: Image<PrimaryImageType.Artnum> = {
id: 1,
imageType: PrimaryImageType.Artnum,
typeID: "asd",
secondaryType: "INVALID", // 应该是无效的
}
英文:
I want to create a type-safe method of assigning secondary keys to an object, depending on the value of a primary type (which is currently an enum). I tried the following, but the type Test
is typed as string
instead of an union of allowed values. How can I achieve this?
export enum PrimaryImageType {
Artnum = "ARTNUM",
RMA = "RMA",
}
export const SecondaryImageTypes: Record<PrimaryImageType, string[]> = {
[PrimaryImageType.Artnum]: [
"LDA_OVP",
"LDA_PALETTE",
"LDA_LABEL",
"LDA_VERPACKHINWEIS",
"LDA_MASTERKARTON",
],
RMA: [
],
};
export type SecondaryType<P extends PrimaryImageType> = typeof SecondaryImageTypes[P][number];
type Test = SecondaryType<PrimaryImageType.Artnum>;
// Test is typed as string, I expect it to be "LDA_OVP" | "LDA_PALETTE" | "LDA_LABEL" | "LDA_VERPACKHINWEIS" | "LDA_MASTERKARTON"
// I want to use those types similar to this:
export interface Image<P extends PrimaryImageType> {
id: number,
imageType: P,
typeID: string,
secondaryType: SecondaryType<P>,
}
// TS should enforce the union of secondary types:
const testImg: Image<PrimaryImageType.Artnum> = {
id: 1,
imageType: PrimaryImageType.Artnum,
typeID: "asd",
secondaryType: "INVALID", // should be invalid
}
答案1
得分: 3
你看到它是string
,因为你将SecondaryImageTypes
声明为Record<PrimaryImageType, string[]>
,而ts不能将string
缩小到你所使用的字面值。
最简单的方法是移除SecondaryImageTypes
的类型定义并对其进行const断言:
export const SecondaryImageTypes = {
[PrimaryImageType.Artnum]: [
'LDA_OVP',
'LDA_PALETTE',
'LDA_LABEL',
'LDA_VERPACKHINWEIS',
'LDA_MASTERKARTON',
],
RMA: [],
} as const;
这样做可以解决你的问题,但SecondaryImageTypes
不是类型安全的,我们可以轻松修复它,感谢satisfies运算符。请注意:satisfies
是在Typescript 4.9中添加的,因此对于先前的版本不起作用。
export const SecondaryImageTypes = {
[PrimaryImageType.Artnum]: [
'LDA_OVP',
'LDA_PALETTE',
'LDA_LABEL',
'LDA_VERPACKHINWEIS',
'LDA_MASTERKARTON',
],
RMA: [],
} as const satisfies Record<PrimaryImageType, readonly string[]>;
// 类型Test = "LDA_OVP" | "LDA_PALETTE" | "LDA_LABEL" | "LDA_VERPACKHINWEIS" | "LDA_MASTERKARTON"
type Test = SecondaryType<PrimaryImageType.Artnum>;
英文:
You see it as string
because you declared SecondaryImageTypes
as Record<PrimaryImageType, string[]>
, and ts can't narrow the string
to the literal values that you have used.
The easiest thing to do is to remove the type definition of SecondaryImageTypes
and const assert it:
export const SecondaryImageTypes = {
[PrimaryImageType.Artnum]: [
'LDA_OVP',
'LDA_PALETTE',
'LDA_LABEL',
'LDA_VERPACKHINWEIS',
'LDA_MASTERKARTON',
],
RMA: [],
} as const;
Doing this will solve your problem, however SecondaryImageTypes
is not type safe and thanks to satisfies operator we can easily fix it.
Note: satisfies
was added in Typescript 4.9 so it will not works for the previous versions.
export const SecondaryImageTypes = {
[PrimaryImageType.Artnum]: [
'LDA_OVP',
'LDA_PALETTE',
'LDA_LABEL',
'LDA_VERPACKHINWEIS',
'LDA_MASTERKARTON',
],
RMA: [],
} as const satisfies Record<PrimaryImageType, readonly string[]>;
// type Test = "LDA_OVP" | "LDA_PALETTE" | "LDA_LABEL" | "LDA_VERPACKHINWEIS" | "LDA_MASTERKARTON"
type Test = SecondaryType<PrimaryImageType.Artnum>;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论