英文:
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").
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论