Interfaces with all optional fields mess things up
Hello. Bad news: I found use case when your implementation fails to notify about incompatible types =( Good news: there is solution =)
In our project we had some interface automatically generated (from protobuf files), so it happened that one interface had all fields optional.
Here's demo (reproducible on https://www.typescriptlang.org/play/index.html):
function tassign<T extends U, U>(target: T, ...source: U[]): T {
return Object.assign({}, target, ...source);
}
// via https://stackoverflow.com/a/41159188
function tassign2<T, K extends keyof T>(target: T, ...source: Pick<T, K>[]): T {
return Object.assign({}, target, ...source);
}
interface MyState {
field: string;
}
const state: MyState = {
field: "value"
};
interface ProtocolThing {
all?: string;
fields?: number;
optional?: boolean;
}
const valueFromProtocol: ProtocolThing = {
all: 'fields are optional'
};
// No error :( it assumes everything is fine
tassign(state, {
field: valueFromProtocol
});
// Argument of type '{ field: ProtocolThing; }' is not assignable to parameter of type 'Pick<MyState, "field">'.
// Types of property 'field' are incompatible.
// Type 'ProtocolThing' is not assignable to type 'string'.
tassign2(state, {
field: valueFromProtocol
});
Also issue with union types:
function tassign<T extends U, U>(target: T, ...source: U[]): T {
return Object.assign({}, target, ...source);
}
// via https://stackoverflow.com/a/41159188
function tassign2<T, K extends keyof T>(target: T, ...source: Pick<T, K>[]): T {
return Object.assign({}, target, ...source);
}
type MyUnionType = 'foo' | 'bar';
interface MyState {
unionField: MyUnionType;
}
const state: MyState = {
unionField: 'foo'
};
// No error :( it assumes everything is fine
tassign(state, {
unionField: 'brr'
});
// Argument of type '{ unionField: "brr"; }' is not assignable to parameter of type 'Pick<MyState, "unionField">'.
// Types of property 'unionField' are incompatible.
// Type '"brr"' is not assignable to type 'MyUnionType
tassign2(state, {
unionField: 'brr'
});
@fljot hey - I don't keep my eye on this repo very much, and didn't notice your issue - we were debating deprecating this repo at some point as TypeScript added features that might make this obsolete, but liking what you've done with tassign2 - will look into updating this with your changes. Just need to see if this will be a possibly breaking change for some people and if it'd be a major bump, or a minor.
Thanks for your insight, and sorry for the long delay in response.