Typescript 如何使这种类型安全?

Typescript 如何使这种类型安全?,typescript,typescript-typings,typescript-generics,Typescript,Typescript Typings,Typescript Generics,我有一个方法(UndefineAllLeapProperties),它将undefined设置为所有“叶”属性,以便在访问任何嵌套属性(叶属性的父属性)时不会给出任何未定义的异常 例: 调用UnfineAllLeafProperties(newPerson());应该给 { name : undefined, age : undefined, address : { street : undefined, city : undefined

我有一个方法(UndefineAllLeapProperties),它将undefined设置为所有“叶”属性,以便在访问任何嵌套属性(叶属性的父属性)时不会给出任何未定义的异常

例:

调用UnfineAllLeafProperties(newPerson());应该给

{
 name : undefined,
age : undefined,
address : { 
            street : undefined,
            city : undefined
           }
}
上述要求的原因是,我只需要填写所需的属性,并在传递给JSON.parse(JSON.stringify(obj))时删除所有属性

问题:当递归调用时,它会抛出一个错误

Argument of type 'T[keyof T]' is not assignable to parameter of type 'object'.
  Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'object'.
    Type 'T[string]' is not assignable to type 'object'.
如何在不使用“任何”的情况下解决此问题


export function undefineAllLeafProperties<T extends object>(obj : T) : T {

    const keys : Array<keyof T> = Object.keys(obj) as Array<keyof T>;

    keys.forEach(key => {
        if (obj[key] && typeof obj[key] === "object") {
            obj[key] = undefineAllLeafProperties(obj[key]); // recursively call the same function
        }
        else {
            obj[key] = undefined;
        }
    });

    return obj;
}

导出函数UnfineAllLeapProperties(对象:T):T{
常量键:数组=对象。键(obj)作为数组;
keys.forEach(key=>{
if(对象[键]&&typeof对象[键]=“对象”){
obj[key]=UndefineAllLeapProperties(obj[key]);//递归调用同一个函数
}
否则{
obj[key]=未定义;
}
});
返回obj;
}

问题在于此表达式不充当类型保护:

typeof obj[key] === "object"
据我所知,没有“干净”的方法来解决这个问题。在递归调用中添加
将解决此错误:

obj[key] = undefineAllLeafProperties(<any>obj[key])
obj[key]=undefineAllLeafProperties(obj[key])

(即使您强制键入
对象
,您仍然会遇到问题,因为函数随后将返回
对象
,该对象不再可分配给
obj[key]

问题在于此表达式不充当类型保护:

typeof obj[key] === "object"
据我所知,没有“干净”的方法来解决这个问题。在递归调用中添加
将解决此错误:

obj[key] = undefineAllLeafProperties(<any>obj[key])
obj[key]=undefineAllLeafProperties(obj[key])
(即使您强制键入
对象
,您仍然会遇到问题,因为函数随后将返回
对象
,该对象不再可分配给
obj[key]

解决方案 下面的代码没有错误,返回类型安全的对象。我所做的改进是:

  • 记录
    对象
    上,记录更具限制性,允许重新分配密钥
  • 映射了
    Undefined
    type,因此TypeScript知道返回类型中的所有值都将是未定义的
  • 作为T[keyof T]
    ,TypeScript不知道我们分配给什么键,因为我们使用泛型。这里的解决方案是将它转换为
    T[keyof T]
    ,让TS放心,我们知道我们在做什么(我希望有更好的解决方案,但我找不到)
  • 我在本例中使用了一个接口,但问题中的类也可以使用

    接口人{
    年龄:人数;
    姓名:{
    第一:字符串;
    最后:字符串;
    };
    }
    警察:人={
    年龄:9岁,
    姓名:{
    第一:“第一”,
    最后:“最后”
    }
    };
    类型Undefined={[P in keyof T]:Undefined};
    导出函数UnfineAllLeafProperties(
    对象:T
    ):未定义{
    Object.keys(obj.forEach)(key:keyof T)=>{
    if(对象[键]&&typeof对象[键]=“对象”){
    obj[key]=未定义的叶子属性(obj[key])作为T[keyof T];
    }否则{
    obj[key]=未定义为T[keyof T];
    }
    });
    返回obj;
    }
    常数pu=未定义的叶属性(p);
    控制台日志(pu);
    
    沙箱:

    可选链 在你的问题中,你提到:

    …以便在访问任何嵌套属性(叶属性的父属性)时不会出现任何未定义的异常


    JavaScript和TypeScript添加了一个功能来解决这个问题,称为可选链接

    let street=person?address?street;
    
    在本例中,如果
    person
    address
    未定义,则不会引发异常,只将未定义分配给
    street

    如果您使用的是TypeScript>=3.7,则可以使用此语法。或者,您可以将Babel与

    在此处了解更多信息:

    解决方案 下面的代码没有错误,返回类型安全的对象。我所做的改进是:

  • 记录
    对象
    上,记录更具限制性,允许重新分配密钥
  • 映射了
    Undefined
    type,因此TypeScript知道返回类型中的所有值都将是未定义的
  • 作为T[keyof T]
    ,TypeScript不知道我们分配给什么键,因为我们使用泛型。这里的解决方案是将它转换为
    T[keyof T]
    ,让TS放心,我们知道我们在做什么(我希望有更好的解决方案,但我找不到)
  • 我在本例中使用了一个接口,但问题中的类也可以使用

    接口人{
    年龄:人数;
    姓名:{
    第一:字符串;
    最后:字符串;
    };
    }
    警察:人={
    年龄:9岁,
    姓名:{
    第一:“第一”,
    最后:“最后”
    }
    };
    类型Undefined={[P in keyof T]:Undefined};
    导出函数UnfineAllLeafProperties(
    对象:T
    ):未定义{
    Object.keys(obj.forEach)(key:keyof T)=>{
    if(对象[键]&&typeof对象[键]=“对象”){
    obj[key]=未定义的叶子属性(obj[key])作为T[keyof T];
    }否则{
    obj[key]=未定义为T[keyof T];
    }
    });
    返回obj;
    }
    常数pu=未定义的叶属性(p);
    控制台日志(pu);
    
    沙箱:

    可选链 在你的问题中,你提到:

    …以便在访问任何嵌套属性(叶属性的父属性)时不会出现任何未定义的异常


    JavaScript和TypeScript添加了一个功能来解决这个问题,称为可选链接

    let street=person?address?street;
    
    在本例中,如果
    person
    address
    未定义,则不会引发异常,只将未定义分配给
    street

    如果您使用的是TypeScript>=3.7,则可以使用此语法。或者,您可以将Babel与


    在此了解更多信息:

    您是否尝试创建地址类并将其用作地址类型