如何在TypeScript中对动态生成的对象使用”as const”?

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

How to use "as const" on dynamically generated objects in TypeScript?

问题

我一直在尝试各种可能的方式和在线解决方案,以在动态对象上使用 "as const",但毫无运气,所以我将非常感激任何帮助。

我试图实现的目标是生成一个对象 THEME_NAME_LIST,其中包含另一个对象 THEME 中使用的键,以便我不必每次某些新键似乎出现在 THEME 对象中时都手动维护 THEME_NAME_LIST 对象。

到目前为止,我已经能够轻松地从我的对象中生成const类型,只限于像这样的静态类型对象;

export const THEME_NAME_LIST = {
    DARK: 'dark',
    LIGHT: 'light',
} as const;

const THEME_ARRAY = Object.values(THEME_NAME_LIST);
export type ThemeType = typeof THEME_ARRAY[number];

当我悬停在 THEME_NAME_LIST.LIGHT 上时,IDE 显示以下消息;

(property) LIGHT: "light"

现在一切都很顺利!但是,当我将 THEME_NAME_LIST 更改为以下示例时,THEME_NAME_LIST 就会出问题!

const THEME = {
    // ...
    DARK: {
        // ...
    },
    LIGHT: {
        // ...
    },
    // ...
};

export const THEME_NAME_LIST = {} as const;
Object.keys(THEME).forEach((key) => {
    const THEME_NAME = key.toUpperCase();
    THEME_NAME_LIST[THEME_NAME] = key.toLowerCase();
});

因此,当我悬停在 THEME_NAME_LIST.LIGHT 上时,IDE 提示以下消息;

Property LIGHT does not exist on type {}

有人能告诉我我做错了什么吗?

英文:

As the title suggests I've been trying every possible way and solution that I could find online to use "as const" on a dynamic object but no luck whatsoever so I would greatly appreciate any help.

What I'm trying to achieve is generating an object THEME_NAME_LIST of the keys used in another object THEME, so that I don't have to manually maintain the THEME_NAME_LIST object every time some supposedly new key gets to the THEME object.

I've been easily able to generate const types from my object up until this point only on statically typed objects like this;

export const THEME_NAME_LIST = {
	DARK: 'dark',
	LIGHT: 'light',
} as const;


const THEME_ARRAY = Object.values(THEME_NAME_LIST);
export type ThemeType = typeof THEME_ARRAY[number];

And when I hover over theTHEME_NAME_LIST.LIGHT, the IDE shows the following message;

> (property) LIGHT: "light"

Now everything up until this point works great!
However, when I change THEME_NAME_LIST to the example below, the THEME_NAME_LIST breaks!

const THEME = {
	// ...
	DARK: {
		// ...
	},
	LIGHT: {
		// ...
	},
	// ...
};

export const THEME_NAME_LIST = {} as const;
Object.keys(THEME).forEach((key) => {
	const THEME_NAME = key.toUpperCase();
	THEME_NAME_LIST[THEME_NAME] = key.toLowerCase();
});

So when I hover THEME_NAME_LIST.LIGHT, the IDE prompts the following message;

> Property LIGHT does not exist on type {}

Is anybody able to tell me what I'm doing wrong?

答案1

得分: 1

const断言并不适用于动态对象。它告诉编译器你的对象是只读的。你上面的代码导致错误 ,当你尝试操作这个对象时。

元素具有 'any' 类型,因为类型为 'string' 的表达式不能用于索引类型为 '{}' 的类型。
  在类型 '{}' 上找不到参数类型为 'string' 的索引签名。(7053)

不要将const应用于你正在创建的对象,而是应用于你原始的对象,并从那里派生类型。我建议创建一个映射类型,如下所示:

type ThemeNameList = {
  [ThemeName in keyof typeof THEME as Uppercase<ThemeName>]: Lowercase<ThemeName>;
};

请注意,诸如Object.keys之类的函数不能保留字符串字面量。你可以在任何时候放置断言,但我建议在导出之前将ThemeNameList作为断言应用于你的新对象。

const _THEME_NAME_LIST: Record<string, unknown> = {};
Object.keys(THEME).forEach((key) => {
  const THEME_NAME = key.toUpperCase();
  _THEME_NAME_LIST[THEME_NAME] = key.toLowerCase();
});

export const THEME_NAME_LIST = _THEME_NAME_LIST as ThemeNameList;
英文:

const assertions are not meant for dynamic objects. It tells the compiler your object is readonly. Your above code gives an error when you try to manipulate the object.

Element implicitly has an &#39;any&#39; type because expression of type &#39;string&#39; can&#39;t be used to index type &#39;{}&#39;.
  No index signature with a parameter of type &#39;string&#39; was found on type &#39;{}&#39;.(7053)

Instead of applying const to the object you're trying to create, apply the const assertion on your original object, and derive types from there. I would suggest creating a mapped type like so:

type ThemeNameList = {
  [ThemeName in keyof typeof THEME as Uppercase&lt;ThemeName&gt;]: Lowercase&lt;ThemeName&gt;;
};

Note that functions like Object.keys won't help preserve string literals. You can place assertions at any point in time, but my suggestion would be to only apply the ThemeNameList as an assertion to your new object right before you export.

const _THEME_NAME_LIST: Record&lt;string, unknown&gt; = {};
Object.keys(THEME).forEach((key) =&gt; {
  const THEME_NAME = key.toUpperCase();
  _THEME_NAME_LIST[THEME_NAME] = key.toLowerCase();
});

export const THEME_NAME_LIST = _THEME_NAME_LIST as ThemeNameList;

huangapple
  • 本文由 发表于 2023年5月30日 08:57:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76361018.html
匿名

发表评论

匿名网友

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

确定