Typescript:具有可选属性的接口不能分配给具有相同但必需属性的类型

时间:2016-06-06 09:22:42

标签: typescript

这是我想做的事情:

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参数的类型安全性的情况下安抚一丝不苟的编译器?

2 个答案:

答案 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' });

code in playground

您的originalchanges属于同一类型,只是每个都有不同的界面定义的属性(基于您的示例)。
你没有两种不同的类型,一种扩展另一种,所以<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' });

code in playground

答案 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);