这是我想做的事情:
const assign = <T extends U, U>(original: T, changes: U) =>
<T>Object.assign({}, original, changes);
interface IFoo {
bar: number,
baz?: string,
quux?: boolean,
}
let foo = <IFoo>{ bar: 42, baz: 'hello' };
assign(foo, { baz: 'world' }); //Compilation Error:
我只想实现类型安全assign
。但编译器抛出错误:
类型&#39; IFoo&#39;不能分配给&#39; {baz:string; }&#39 ;. 物业&#39; baz&#39;在类型&#39; IFoo&#39;中是可选的但需要类型&#39; {baz:string; }&#39;
changes
类型的属性应始终是original
类型的严格子集,我认为这种赋值应完全合乎逻辑。
如何绕过它,在不牺牲changes
参数的类型安全性的情况下安抚一丝不苟的编译器?
答案 0 :(得分:1)
如果我理解你的话,你的仿制品就错了。
应该是:
const assign = <T>(original: T, changes: T) => <T> Object.assign({}, original, changes);
interface IFoo {
bar?: number;
baz?: string;
quux?: boolean;
}
let foo = <IFoo> { bar: 42, baz: 'hello' };
assign(foo, { baz: 'world' });
您的original
和changes
属于同一类型,只是每个都有不同的界面定义的属性(基于您的示例)。
你没有两种不同的类型,一种扩展另一种,所以<T extends U, U>
是错误的。
此外,由于您希望只能在界面中拥有属性的子集,因此您必须使它们都是可选的,否则您将收到编译错误。
根据您的评论,这可能对您有用:
const assign = <T extends U, U>(original: T, changes: U) => <T> Object.assign({}, original, changes);
interface FooOptional {
baz?: string;
quux?: boolean;
}
interface FooMandatory extends FooOptional {
bar: number;
}
let foo = { bar: 42, baz: 'hello' };
assign(foo, { baz: 'world' });
答案 1 :(得分:0)
你真的需要T extends U
assign
,因为你只是&#34;只有&#34;对U的类型检查感兴趣
const assign = <T, U>(original: T, changes: U) => <T> Object.assign({}, original, changes);
U可以定义为
interface U {
baz: string
}
let foo = <IFoo>{ bar: 42, baz: 'hello' };
let u: U = { baz: 'world' }
assign(foo, u);