如果我有一个允许值的枚举,例如:
enum PackagingUnits {
Be = 'becher',
Bg = 'bogen',
Bi = 'bidon'
}
我希望函数通过键传递一个字符串以获取枚举值,因此getPackagingUnitName('Be')
将返回'becher'
。
这个天真的版本是:
function getPackagingUnitName(key: string): PackagingUnits | null {
if (PackagingUnits[key]) {
return PackagingUnits[key]
}
return null
}
但是,TypeScript(版本3.3.3 atm)不喜欢这样,并且抱怨Element implicitly has an 'any' type because index expression is not of type 'number'.
的每个实例都PackagingUnits[key]
。
我尝试了if条件的一些变体(例如Object.keys(PackagingUnits).includes(key)
,它使if条件无错误,但是对于return语句return PackagingUnits[key]
仍然给出相同的错误。
return PackagingUnits[key as PackagingUnits]
也不起作用。
我唯一能想到的有效语法是:
function getPackagingUnitName(key: string): PackagingUnits | null {
const puIndex = Object.keys(PackagingUnits).indexOf(key)
if (puIndex !== -1) {
return Object.values(PackagingUnits)[puIndex]
}
return null
}
这真的是最好的方法吗?
N.B .:是的,如果PackagingUnits
不是枚举,则可以更轻松地完成此操作,但对于其他用途则需要这样做。
答案 0 :(得分:3)
TypeScript不会将访问未知属性视为缩小控制流以断言该属性存在的一种方式。仅当编译器知道该键处有一个属性(或在使用可选属性的情况下)时,才可以访问对象类型的属性。因此,一旦您执行PackagingUnits[key]
,其中key
是任意string
时,编译器就会抱怨PackagingUnits
没有string
索引。
最简单的解决方法是使用type assertion并继续:
function getPackagingUnitName(key: string): PackagingUnits | null {
if ((PackagingUnits as any)[key]) { // assert your way out
return PackagingUnits[key as keyof typeof PackagingUnits]; // assert your way out
}
return null;
}
这有效,但不能保证编译器的类型安全。您可能不在乎,因为问题出在其他开发人员不会使用的功能的实现中。如果是这样,那就太好了。
如果希望编译器保证所执行的操作是类型安全的,则需要通过仔细的步骤引导其进行分析。首先,您希望编译器不要将PackagingUnits
对象当作具有三个已知值为PackagingUnits
类型的键的对象来对待,而是将其视为值为 every < / em>字符串键,其值为PackagingUnits | undefined
。 (由于TypeScript并不总是optional index signatures,因此距离distinguish missing properties from undefined
-values properties很近)。所以你想要这样:
const PackagingUnitsIndexSignature: {[k: string]: PackagingUnits | undefined} =
PackagingUnits; // error!
这应该是安全的(类型typeof PackagingUnits
是typeof PackagingUnitsIndexSignature
的严格subtype),但是编译器没有意识到。 enum
的{{1}}性质似乎使它感到困惑。因此,我们可以分两步进行扩展...首先是将其键和值与枚举的键和值相匹配的普通对象类型:
PackagingUnits
现在我们终于有了可以用const PackagingUnitsPlainObject: Record<keyof typeof PackagingUnits, PackagingUnits> =
PackagingUnits; // okay!
const PackagingUnitsIndexSignature: { [k: string]: PackagingUnits | undefined } =
PackagingUnitsPlainObject; // okay!
进行索引的东西了,没有错误:
string
U,发生了什么事?由于我们刚刚检查了function getPackagingUnitName(key: string): PackagingUnits | null {
if (PackagingUnitsIndexSignature[key]) { // okay!
return PackagingUnitsIndexSignature[key]; // error!!!!
} else {
return null;
}
}
处某个属性的存在,是否应该控制流量收窄工作?不幸的是,bracket-type indexed access doesn't always narrow values the way we'd like。让我们以key
返回PackagingUnitsIndexSignature[key]
为前提,而不是强制执行此操作。如果是这样,我们应该可以使用logical "or" (||
) operator将PackagingUnits | undefined
替换为undefined
:
null
编译器很高兴。综上所述,这是编写相同逻辑的一种round回方式,以便编译器确认其类型安全:
function getPackagingUnitName(key: string): PackagingUnits | null {
return PackagingUnitsIndexSignature[key] || null; // okay
}
好的,希望能有所帮助。祝你好运!
答案 1 :(得分:1)
您尝试过
function getPackagingUnitName(key: keyof typeof PackagingUnits): PackagingUnits | null {
if (PackagingUnits[key]) {
return PackagingUnits[key];
}
return null
}
当然,以防万一,key
是从API或类似的东西获得的。否则,该功能不是真正必需的。如果要进行类型检查以确保键是预定义值之一,只需使用
key: keyof typeof PackagingUnits;