我在使用Typescript的查询中使用GraphQL和自动生成的类型。它倾向于创建很多嵌套的type | null
类型。因此,我需要对非null值进行相当长的检查。例如
data &&
data.getCoach &&
data.getCoach.workouts &&
data.getCoach.workouts.items &&
data.getCoach.workouts.items.map((workout) => {/* do something*/});
我尝试使用lodash has
助手来检查路径是否存在
has('getCoach.workouts.items', data) &&
data.getCoach.workouts.items.map((workout) => {/* do something*/});
但是ts编译器似乎不理解这一点。
除了让我的GraphQL端点始终返回值之外,还有更好的方法进行检查吗?
答案 0 :(得分:1)
TypeScript的功能不足以表示您要执行的操作。理想情况下,JavaScript和TypeScript将具有null-coalescing operator,您将使用它。但是它没有那个。
如果尝试强力键入lodash has
方法,则会发现编译器无法concatenate string literal types或执行regular expression operations on them,因此编译器无法采用字符串'getCoach.workouts.items'
并了解getCoach
将是data
的键,而workouts
将是data.getCoach
的键,等等。
即使不使用has
,表示此处涉及的嵌套类型操作也很棘手,而不会遇到recursion这样会使编译器生气或崩溃的问题。
我能做的最好的事情是:将对象包装在Proxy(需要ES2015或更高版本)中,该对象在您要使用的任何键上始终具有值,并且使用特殊的键名(例如{ {1}})提取属性的实际值,如果没有,则返回"value"
。这是实现:
undefined
现在,代替这个:
type WrapProperties<T, K extends keyof any> = Record<K, T> & { [P in keyof T]-?: WrapProperties<T[P], K> }
function wrapProperties<T>(val: T): WrapProperties<T, "value">;
function wrapProperties<T, K extends keyof any>(val: T, valueProp: K): WrapProperties<T, K>;
function wrapProperties(val: any, valueProp: keyof any = "value"): WrapProperties<any, any> {
return new Proxy({}, {
get: (_, p) => p === valueProp ? val : wrapProperties(
(typeof val === 'undefined') || (val === null) ? val : val[p], valueProp
)
});
}
您应该能够做到这一点:
if (data && data.getCoach && data.getCoach.workouts && data.getCoach.workouts.items) {
data.getCoach.workouts.items.map((workout) => {/* do something*/})
}
我不知道实现是否完美。当我尝试它似乎工作。与从Stack Overflow获得的任何内容一样,您的里程可能会有所不同,并且需要注意。也许会对您有帮助。祝你好运!
答案 1 :(得分:0)
以为我刚才提到nullish coalescing已进入TC39的第二阶段!
我认为目前还没有任何灵巧的解决方案,因此,现在也许必须做类似jcalz的回答。
希望TS像他们对async / await所做的那样尽早引入它,我可以更新此答案。