如何对多层深度的对象强制执行空检查?

How to enforce null checking for objects multiple layers deep?

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

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

我想对数据对象(必须是任何类型)强制执行 null 检查,以便当其他开发人员尝试写入时

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

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

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

}

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

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

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;

}

有点冗长,但可能有用。