问题描述
export const IconSizeMap = {
'extra-small': '0.75rem',small: '1rem',medium: '1.5rem',large: '2rem','extra-large': '4rem'
};
对打字稿不熟悉,我无法理解错误是什么
出现错误
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ 'extra-small': string; small: string; medium: string; large: string; 'extra-large': string; }'.
No index signature with a parameter of type 'string' was found on type '{ 'extra-small': string; small: string; medium: string; large: string; 'extra-large': string; }'.ts(7053)
当我尝试使用
IconSizeMap[size]
解决方法
IconSizeMap[size]
试图将字符串用作未使用字符串索引定义的对象的索引,这就是为什么会出现此错误的原因。
您的选择是:
-
向对象添加string index signature,或者
-
不要使用通用字符串将对象编入索引
您要做什么取决于您的用例。索引签名意味着TypeScript无法主动检查size
是否与对象的属性匹配。但是,仅使用特定的属性名称意味着,如果起始点是可以有任何值的字符串,则将这些属性名称列出多个位置。
这里是#1的示例:
export const IconSizeMap: {[key: string]: string} = {
// −−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^
'extra-small': '0.75rem',small: '1rem',medium: '1.5rem',large: '2rem','extra-large': '4rem'
};
这里是#2的示例:
function getIconSize(size: string) {
switch (size) {
case 'extra-small':
return IconSizeMap['extra-small'];
case 'small':
return IconSizeMap.small;
case 'medium':
return IconSizeMap.medium;
case 'large':
return IconSizeMap.large;
case 'extra-large':
return IconSizeMap['extra-large'];
default:
throw new Error(`Invalid 'size' for IconSizeMap: ${size}`);
}
}
请注意在访问对象时我们如何使用特定的字符串文字,而不仅仅是任何字符串。
,您收到此错误,因为您的tsconfig.json
已启用"noImplicitAny": true
。这意味着TypeScript将查找并通知您使用未知类型的值的地方,以及您未明确告诉他应该使用哪种类型的地方。
您可以采用以下方法解决此问题:
- 在配置中禁用
noImplicitAny
(但是我想这是有原因的,因此我不建议这样做) - 告诉TypeScript您正在使用的类型会导致错误。
在这里,TypeScript可以识别您定义的5个键(extra-small
,small
,medium
,large
和extra-large
)中的每一个,因为您分配了一个值是string
,因此可以判断它们是字符串。但是,只有这5个string
是键。
当您使用“通用” string
访问对象(例如我假设您的size
是)时,您不确定它是否对应于5个键之一。因此,TypeScript会警告您。
一种解决方案是,告诉编译器您正在执行的操作确定,并更精确地指定size
的类型。例如:
export const IconSizeMap = {
'extra-small': '0.75rem','extra-large': '4rem'
};
let size: keyof typeof IconSizeMap; // Means "I'm sure that size is one of those strings
size = "small";
console.log(IconSizeMap[size]);
,
自T.J. Crowder的回答是正确的,我只是添加一些注释,以防它有助于更好地了解正在发生的事情。
您必须记住TypeScript为JavaScript添加了静态类型。这意味着用该语言定义的每个实体都有一个确定的类型,无论是由您定义还是由TypeScript隐式推断,TypeScript都将强制遵守该类型。
在您的情况下,TypeScript隐式推断您的IconSizeMap
对象是确定类型。它不是可以具有任何字符串键的通用JavaScript对象,而是具有某些确定键的对象:extra-small
,small
等。TypeScript可以从您对对象的定义中推断出这一点。
一旦TypeScript为实体推断出类型,它将为您每次使用该实体强制执行。这意味着,如果您尝试使用类似IconSizeMap['huge']
之类的方法,则会因'huge'
未以TypeScript推断的类型注册为有效键而抱怨。
这很容易理解,因为'huge'
没有明确包含在对象中。但这会带来棘手的后果,就像您提到的问题一样。如果您使用字符串类型的变量size
访问对象属性,那么TypeScript也会抱怨,因为size
的值可能是未注册为对象键之一的字符串。这就是T.J.解决方案的原因:
- 您可以将对象的类型明确定义为允许任何字符串键。
- 您限制引用对象键的字符串变量的类型,以使它们不能是任何字符串,而只能是对象中包含的字符串之一。
我想第二种解决方案就是您所需要的,因为您的对象似乎是固定的映射,因此不允许进一步的字符串键。您可以让TypeScript隐式地推断出这一点,就像T.J的解决方案中那样,该解决方案使用仅带有预期字符串文字的开关。
但是,在这种情况下,有时我会明确定义包含这些字符串文字的并集类型。例如:
type IconSize = 'extra-small' | 'small' | 'medium' | 'large ' | 'extra-large';
然后我可以用该类型显式定义变量,而TypeScript将帮助我避免为该变量分配不同的字符串值:
let size: IconSize;
这意味着TypeScript将排除尝试将其他字符串值设置为size
的任何尝试。由于size
将具有预期值之一,因此下次尝试IconSizeMap[size]
TypeScript时不会抱怨。