首页 > 解决方案 > 如何对多层深的对象强制执行空检查?

问题描述

我正在使用 redux sagas 通过一个通用接口从多个端点异步获取数据:

export interface ResponseInfo {
    data?: any;
    status: number;
    headers?: any;
    subCode?: string;
}

我想对数据对象(必须是 any 类型)强制执行 null 检查,以便当另一个开发人员尝试编写

if(response.data.pizza.toppings){}

除非他或她添加空检查,否则它将无法编译,

if(response.data && response.data.pizza && response.data.pizza.toppings){

}

我们正在使用打字稿,但--strictNullChecks不会在没有空检查的情况下标记上述行。这是 tslint 中no-unsafe-any的用途吗?有没有办法让打字稿自己做这个检查?

标签: javascripttypescriptredux-saga

解决方案


我们可以使用带有索引签名的接口来定义这样的对象:

export interface ResponseInfo {
    data?: RecursiveObject;
    status: number;
    headers?: any;
    subCode?: string;
}

interface RecursiveObject {
    [s: string]: RecursiveObject | undefined
}

// Usage 

declare let response : ResponseInfo
if(response.data.pizza.toppings){ // Object is possibly 'undefined'

}

if(response.data.pizza){ // Object is possibly 'undefined'

}

一个问题是response.data.pizza.toppings不是RecursiveObject很有用。为了解决这个问题(并且也更加安全),我们可以使用自定义类型保护来将最终结果的类型缩小到有用的范围内。(请注意,常规类型保护不起作用,因为RecursiveObject与字符串无关,而简单的保护例如typeof response.data.pizza.toppings === 'string'实际上会缩小到never

function isString(o: RecursiveObject|string ): o is string {
    return typeof o === "string"
}

declare let response : ResponseInfo
if(response.data && response.data.pizza && response.data.pizza.toppings
    && isString(response.data.pizza.toppings) ){
    let s : string = response.data.pizza.toppings;

}

有点冗长,但可能有用。


推荐阅读