我正在尝试编写一些数据验证助手,以确保 TypeScript 编译器
function process(data: unknown) {
assert(data instanceof Object);
// need a helper for this line
assert( hasSubobject(data, 'some_field') );
// so that this line doesn't complain about `some_field` not existing
assert(typeof data.some_field === 'string');
// …
}
我知道我可以将其硬编码为'some_field' in data && data.some_field instanceof Object
内联,甚至发现我可以硬编码一个助手,例如:
function hasHardcodedSubobject(data: object): data is {hardcodedField: object} {
return (
"hardcodedField" in data &&
data.hardcodedField instanceof Object
);
}
但我不确定如何将其转换为更动态的东西,例如:
function hasSubobject(data: object, key: string): data is {[key]: object} {
return (
key in data &&
data[key] instanceof Object
);
}
这有点类似于https://stackoverflow.com/a/68959950/179583,在这种情况下,解决方案可以仅使用“key”作为变量key is keyof T
,但由于某种原因,我无法以我的方式使用它。它给:
类型文字中的计算属性名称必须引用类型为文字类型或“唯一符号”type.ts(1170) 的表达式
即使key: string
它的类型是文字(更新:我可能混淆了“文字”与“原始”!)类型,即string
?
您的
hasSubobject
函数需要泛型类型。一个用于捕获您传入的对象类型,另一个用于您验证的密钥。这
T
是正在验证的对象类型,K
os 是将缩小的键名。返回值是一个类型谓词,它
T
与一个对象类型相交,其中属性K
被锁定为一个object
类型。这
data[key as unknown as keyof T]
是不幸的,但 Typescript 似乎无法跟踪这key
是一个 keyofT
,但这肯定是由于key in data
检查造成的。所以我们可以在这里用强有力的断言来覆盖它。查看游乐场
通过删除我在较旧的 TypeScript 线程中找到的一些代码,我能够制作出几乎可以工作的东西:
我说“几乎”是因为我必须告诉编译器忽略它
data[key]
即使在我检查之后也会感到不安key in data
,所以这可能不是一个理想的解决方案:-/