我想对已知类型的对象进行Object.assign
,即对象文字中应具有相同类型的一组属性。是否有一种更干净的方法可以在TypeScript中执行此操作,而无需实际调用标识函数或创建单独的变量,如本related question中所建议的那样?
type Person = {
first?: string;
last?: string;
}
// Overkill, actually generates code to call a function
function check<T>(value: T): T { return value; }
const dude: Person = {
first: 'Mike',
};
Object.assign(dude, check<Person>({ // <- trying not to call a function
last: 'Johnson',
age: 27, // <-- should be flagged as unknown property
}));
TL; DR-寻找一种直接键入检查对象文字的方法。
为什么花花公子是一个常量,如果要使用Object.assign进行处理呢?
通常,如果您尝试分配不是'Person'的任何东西,则会出现错误,例如。
type Person = {
first?: string;
last?: string;
}
let dude: Person = {
first: 'Mike',
};
dude = {
last: 'Johnson',
age: 27
} // Error: Not assignable to type Person
这将对分配进行类型检查,如果要分配给常数,也会显示错误。
我想不出一种在所有情况下都可行的“完美”解决方案。大多数说服编译器执行所需类型检查的机制还附带了一些添加的运行时代码(例如,新的中间变量赋值或调用标识函数),而您却不想这么做。
一个问题是TypeScript没有内联类型注释。 (有关讨论,请参见microsoft/TypeScript#7481和microsoft/TypeScript#13208。)您希望能够使编译器verify表达式 exact{...}
的类型为Person
,并让编译器抱怨该表达式无法验证。我们在TypeScript中拥有的最接近的运算符是格式为type assertion的{...} as Person
。但是,这使编译器认为表达式{...}
的类型为Person
。您要询问。
即使我们有一个内联注释运算符,也存在另一个问题:TypeScript中的对象类型不是Person
的对象,那么您将了解其first
和last
属性,但是您实际上对任何其他属性一无所知。仅仅因为Person
的定义没有提及age
属性,所以[[并不意味着类型Person
的对象不能具有age
属性。可能会有这样的界面:interface AgedPerson extends Person {
age: number;
}
{last: "Johnson", age: 27}
(即使未定义AgedPerson
),它也是有效的AgedPerson
。并且由于AgedPerson
是Person
的有效子类型,因此{last: "Johnson", age: 27}
也是有效的Person
。 现在,当人们使用诸如{last: "Johnson", age: 27}
之类的对象文字时,他们通常不打算添加此类额外的属性,因此TypeScript具有一个名为excess property checking的功能,该功能将对象文字视为它们的类型完全相同,如果添加则抱怨未知的属性。此功能很有用,但很容易绕开。因此,重要的是要提一下,如果您完全重构代码,则age
是多余属性的警告可能会消失:
const ageDude = { last: 'Johnson', age: 27 }; const personDude: Person = ageDude; // no error
话虽如此,对于您给出的特定示例,我建议的解决方案是:Object.assign<Person, Person>(dude, { last: 'Johnson', age: 27, // error });
这里您是在对
Object.assign
的调用上手动指定通用类型参数,其中第一个类型参数对应于第一个函数参数的类型,第二个类型参数对应于第二个函数参数的类型。您希望编译器将两者都视为Person
,因此应编写Object.assign<Person, Person>(...)
。并出现预期的多余属性错误。
好的,希望能有所帮助;祝你好运!
Playground link to code