我在项目中遇到了以下问题(摘要),如果做错了事,我真的很困惑:
const fooState = {
normal: {
normalProp: "string",
},
normal2: {
normalProp: 0,
},
weird: {
weirdProp: "anything",
},
};
type fooKeys = keyof typeof fooState;
export const getFooState = <T1 extends fooKeys>(arg: T1) => {
const foundState = fooState[arg];
if ("weirdProp" in foundState) {
console.log(foundState.weirdProp); // This line throws an error, even though it is a practical possibility.
}
return foundState;
};
代码足以说明我的问题。我的目标是在foundState
对象具有特定属性时以不同方式处理特定情况。
在我的示例中,如果参数arg
作为"weird"
传递,则控制台日志将/应该触发,但TS引发错误。为什么呢?
我很感谢所有答案。
答案 0 :(得分:0)
好像打字稿需要为您的案例提供显式的类型保护。定义简单的单级类型保护功能的动态方法是
function dynamicCheckTopLevel<V>(a:any,b:V): a is V {
let keys = Object.keys(b)
return keys.every(k => k in a)
}
您还可以使用专门用于该道具的类型保护,这样您就可以显式地知道该类型,而不是派生自具有键值样本值的传入对象
function weirdCheck(x:any): x is {weirdProp:any}{
return x.weirdProp;
}
然后错误消失
export const getFooState = <T1 extends fooKeys>(arg: T1) => {
const foundState = fooState[arg];
if (dynamicCheckTopLevel(foundState, {weirdProp:5})) { //had to give weirdProp a value, for your purpose it can be anything
console.log(foundState.weirdProp);
}
return foundState;
};
如果您想使用更深层次的动态类型防护,可以使用
function dynamicDeepCheck<V>(a:any,b:V): a is V {
let keys = Object.keys(b) as Array<keyof V>
return keys.every(key => {
if(typeof b[key] === "object"){
return dynamicDeepCheck(a[key], b[key])
}
return (a[key] && typeof a[key] === typeof b[key])
})
}
在顶级类型防护中,由于您的隐式类型防护条件似乎并不在乎prop的值,因此我省略了值类型匹配检查。