如何在严格检查对象的嵌套属性的同时优雅地覆盖对象

时间:2018-06-15 02:16:52

标签: typescript

如果我们有

interface Human{
  name:string
  age:number
  dimensions : {
    height:number
    width:number
  }
}

const base : Human ={
  name:"Base",
  age:12,
  dimensions : {
    height:190,
    width:99
  }
};


const child : Human = lodashMerge(base,{
  age:22,
  dimentions:{
     height:99
  }
}) // this should work , shouldn't throw 


const child2 : Human = lodashMerge(base,{
  hairColor:'red'
}) // should throw because hairColor does not exist in base 

2 个答案:

答案 0 :(得分:2)

假设lodashMerge是lodash的_.merge方法,您将无法执行此操作并继续单独使用该方法。你必须将它包装到你自己的函数中,你可以添加更严格的类型定义,因为lodash本身给出的定义过于宽松。

The type definition for that method can be found here,正如您所看到的,每个重载的返回类型只是其参数的交集类型,听起来您希望返回类型恰好是第一个参数的类型。

所以我建议使用你想要的签名将方法包装到你自己的函数中。这样的事情可能是:

// Using only the final overload (the variadic one), since thats how we call it later.
declare function lodashMerge(object: any, ...otherArgs: any[]): any;

type DeepPartial<T> = {
    [K in keyof T]?: DeepPartial<T[K]>;
}

function myMerge<T>(base: T, ...args: DeepPartial<T>[]): T {
    return lodashMerge(base, ...args);
};

然后,使用它,您将在第二个示例中出现错误,但不会在第一个示例上出现错误。 虽然实际上,由于拼写错误的“尺寸”,因此两者都会出错:

// No problem, works as expected.
const child : Human = myMerge(base,{
  age:22,
  dimensions:{ // Note the change in spelling, otherwise: error.
     height:99
  }
})

// Error: See below
const child2 : Human = myMerge(base,{
  hairColor:'red' // Error: Object literal may only specify known properties, and 'hairColor' does not exist in type 'DeepPartial<Human>'.
})

答案 1 :(得分:0)

您的示例代码遗漏了确定是否将检测到错误的位。这取决于lodashMerge的定义方式。

如果要传递部分对象,请将Partial<Human>视为lodashMerge函数的参数类型。否则,您可以{ age: 99 } as any绕过类型检查。