枚举作为泛型参数,强制执行次要类型

huangapple go评论54阅读模式
英文:

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", // 应该是无效的
}

Playground 链接

英文:

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 = &quot;ARTNUM&quot;,
  RMA = &quot;RMA&quot;,
}

export const SecondaryImageTypes: Record&lt;PrimaryImageType, string[]&gt; = {
  [PrimaryImageType.Artnum]: [
    &quot;LDA_OVP&quot;,
    &quot;LDA_PALETTE&quot;,
    &quot;LDA_LABEL&quot;,
    &quot;LDA_VERPACKHINWEIS&quot;,
    &quot;LDA_MASTERKARTON&quot;,
  ],
  RMA: [
  ],
};

export type SecondaryType&lt;P extends PrimaryImageType&gt; = typeof SecondaryImageTypes[P][number];

type Test =  SecondaryType&lt;PrimaryImageType.Artnum&gt;;
//   Test is typed as string, I expect it to be &quot;LDA_OVP&quot; | &quot;LDA_PALETTE&quot; | &quot;LDA_LABEL&quot; | &quot;LDA_VERPACKHINWEIS&quot; | &quot;LDA_MASTERKARTON&quot;


// I want to use those types similar to this:
export interface Image&lt;P extends PrimaryImageType&gt; {
  id: number,
  imageType: P,
  typeID: string,
  secondaryType: SecondaryType&lt;P&gt;,
}

// TS should enforce the union of secondary types:
const testImg: Image&lt;PrimaryImageType.Artnum&gt; = {
  id: 1,
  imageType: PrimaryImageType.Artnum,
  typeID: &quot;asd&quot;,
  secondaryType: &quot;INVALID&quot;, // should be invalid
}

Playground Link

答案1

得分: 3

你看到它是string,因为你将SecondaryImageTypes声明为Record&lt;PrimaryImageType, string[]&gt;,而ts不能将string缩小到你所使用的字面值。

最简单的方法是移除SecondaryImageTypes的类型定义并对其进行const断言

export const SecondaryImageTypes = {
  [PrimaryImageType.Artnum]: [
    &#39;LDA_OVP&#39;,
    &#39;LDA_PALETTE&#39;,
    &#39;LDA_LABEL&#39;,
    &#39;LDA_VERPACKHINWEIS&#39;,
    &#39;LDA_MASTERKARTON&#39;,
  ],
  RMA: [],
} as const;

这样做可以解决你的问题,但SecondaryImageTypes不是类型安全的,我们可以轻松修复它,感谢satisfies运算符。请注意:satisfies是在Typescript 4.9中添加的,因此对于先前的版本不起作用。

export const SecondaryImageTypes = {
  [PrimaryImageType.Artnum]: [
    &#39;LDA_OVP&#39;,
    &#39;LDA_PALETTE&#39;,
    &#39;LDA_LABEL&#39;,
    &#39;LDA_VERPACKHINWEIS&#39;,
    &#39;LDA_MASTERKARTON&#39;,
  ],
  RMA: [],
} as const satisfies Record&lt;PrimaryImageType, readonly string[]&gt;;
// 类型Test = &quot;LDA_OVP&quot; | &quot;LDA_PALETTE&quot; | &quot;LDA_LABEL&quot; | &quot;LDA_VERPACKHINWEIS&quot; | &quot;LDA_MASTERKARTON&quot;
type Test = SecondaryType&lt;PrimaryImageType.Artnum&gt;;
英文:

You see it as string because you declared SecondaryImageTypes as Record&lt;PrimaryImageType, string[]&gt;, 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]: [
    &#39;LDA_OVP&#39;,
    &#39;LDA_PALETTE&#39;,
    &#39;LDA_LABEL&#39;,
    &#39;LDA_VERPACKHINWEIS&#39;,
    &#39;LDA_MASTERKARTON&#39;,
  ],
  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]: [
    &#39;LDA_OVP&#39;,
    &#39;LDA_PALETTE&#39;,
    &#39;LDA_LABEL&#39;,
    &#39;LDA_VERPACKHINWEIS&#39;,
    &#39;LDA_MASTERKARTON&#39;,
  ],
  RMA: [],
} as const satisfies Record&lt;PrimaryImageType, readonly string[]&gt;;
// type Test = &quot;LDA_OVP&quot; | &quot;LDA_PALETTE&quot; | &quot;LDA_LABEL&quot; | &quot;LDA_VERPACKHINWEIS&quot; | &quot;LDA_MASTERKARTON&quot;
type Test = SecondaryType&lt;PrimaryImageType.Artnum&gt;;

playground

huangapple
  • 本文由 发表于 2023年5月10日 17:58:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76217096.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定