英文:
Typescript - Type 'String' Can't Be Used To Index - React Dynamic Component Name Map
问题
以下是已翻译的内容:
我已经让以下部分运作,并且正在尝试将其转换为TypeScript,但虽然我在某种程度上理解错误,但我不确定如何实际修复它。
我当前允许一个组件拥有一个名为“icon”的属性,它是一个字符串,然后这个字符串会被转换成一个要加载的组件名称。
icons/index.ts
import { BellIcon } from "./BellIcon";
export const iconMap = {
BellIcon
};
iconButton.tsx
import { iconMap } from "./icons";
type IconButtonProps = {
icon: string;
label?: string;
direction?: string;
onClick: () => void;
};
引发错误的行:
const IconElement = iconMap[icon];
这是我得到的两个错误:
元素具有隐式 'any' 类型,因为类型为 'string' 的表达式不能用于索引类型为 '{ BellIcon: (props: any) => Element; }' 的类型。
在类型 '{ BellIcon: (props: any) => Element; }' 上找不到带有类型 'string' 的参数的索引签名。ts(7053)
页面下方的代码是为了获取动态加载的组件的上下文:
<IconElement />
我尝试设置各种类型,但找不到解决问题的方法,更多地是在猜测,我实际上想理解这个问题。
英文:
I've got the following working and I'm trying to convert it to Typescript but whilst I somewhat understand the error, I'm not sure how to go about actually fixing it.
I am currently allowing a component to have a prop of "icon" which is a string and this string is then translating to a component name to be loaded.
icons/index.ts
import { BellIcon } from "./BellIcon";
export const iconMap = {
BellIcon
};
iconButton.tsx
import { iconMap } from "./icons";
type IconButtonProps = {
icon: string;
label?: string;
direction?: string;
onClick: () => void;
};
The offending line:
const IconElement = iconMap[icon];
This is what I get as the two errors:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ BellIcon: (props: any) => Element; }'.
No index signature with a parameter of type 'string' was found on type '{ BellIcon: (props: any) => Element; }'.ts(7053)
Further down the page then for context I am calling the following to get the dynamic component loaded:
<IconElement />
I've tried setting various types but can't find anything that solves the problem, was more trying to guess and I'd actually like to understand the issue.
答案1
得分: 3
需要将icon
属性的类型更改为仅接受iconMap
对象的键。
import { iconMap } from "./icons";
type IconButtonProps = {
icon: keyof typeof iconMap;
label?: string;
direction?: string;
onClick: () => void;
};
英文:
You need to change the type of the icon
prop to only accept keys of the iconMap
object.
import { iconMap } from "./icons";
type IconButtonProps = {
icon: keyof typeof iconMap;
label?: string;
direction?: string;
onClick: () => void;
};
答案2
得分: 2
@emeraldsanto的回答是正确的,但为了添加一些更多细节:
当你定义一个对象如下:
const MyMap = {
foo: 'bar'
};
TypeScript 在处理键时采取严格的方法,并推断类型为:
{
foo: string;
}
这意味着只有键 "foo"
被接受为此映射中的有效属性。你可以通过明确设置类型来覆盖这一点:
const MyMap: {[key: string]: string} = {
foo: 'bar'
};
或者
const MyMap: Record<string, string> = {
foo: 'bar'
};
(这些之间存在一些微妙的差异,但在这种情况下将起同样的作用。)现在 TypeScript 知道任何字符串都是 MyMap
的有效键。
要更严格一些,你可以使用 as const
表示你的对象应该被视为不可变的:
const MyMap = {
foo: 'bar'
} as const;
现在 TypeScript 以最严格的方式推断类型:
{
readonly foo: 'bar';
}
这可能是有益的,因为现在 MyMap.foo
可以在只接受 'bar'
而不是任何字符串的上下文中使用,并且如果你尝试将其与它知道是不正确的内容进行比较,例如 if (MyMap.foo === 'spam')
,TypeScript 将会给出错误。
英文:
@emeraldsanto's answer is correct, but to add some more detail:
When you define an object like
const MyMap = {
foo: 'bar'
};
Typescript takes a strict approach w/r/t keys and infers the type as
{
foo: string;
}
This means that only the key "foo"
is accepted as a valid property in this map. You can override this by setting the type explicitly:
const MyMap: {[key: string]: string} = {
foo: 'bar'
};
or
const MyMap: Record<string, string> = {
foo: 'bar'
};
(These have some subtle differences, but in this case will work the same.) Now TS knows that any string is a valid key for MyMap
.
To go stricter, you can use as const
to indicate that your object should be treated as frozen:
const MyMap = {
foo: 'bar'
} as const;
Now TS infers the type in the strictest way:
{
readonly foo: 'bar'
};
This can be beneficial, as now MyMap.foo
can be used in contexts that only accept "bar"
, not any string, and TS will give you an error if you try to compare to something it knows is incorrect, like if (MyMap.foo === "spam")
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论