Open
Description
Object assign is defined like below in TS:
interface ObjectConstructor {
/**
* Copy the values of all of the enumerable own properties from one or more source objects to a
* target object. Returns the target object.
* @param target The target object to copy to.
* @param source The source object from which to copy properties.
*/
assign<T, U>(target: T, source: U): T & U;
}
Though from MDN it is only copying members that are enumerable:
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
So if U
above has non-enumerable members, TS will copy them anyway. This is slightly incorrect and unsafe.
One issue I recently ran into was
const selection = Object.assign({}, window.getSelection());
I was assuming I was copying all members of the Selection
object to {}
:
interface Selection {
readonly anchorNode: Node;
readonly anchorOffset: number;
// etc ...
}
declare var Selection: {
prototype: Selection;
new(): Selection;
}
Though it didn't copy any members at all, because the Selection
object only contains non-enumerable members.
Proposal
Mark properties as non-enumerable
interface Selection {
readonly nonenum anchorNode: Node;
readonly nonenum anchorOffset: number;
// etc ...
}
And have an operator to get the only "enum side" of a type:
interface ObjectConstructor {
/**
* Copy the values of all of the enumerable own properties from one or more source objects to a
* target object. Returns the target object.
* @param target The target object to copy to.
* @param source The source object from which to copy properties.
*/
assign<T, U>(target: T, source: U): T & enumsof U;
}