Skip to content

Bug Report + Proposal: Object.assign() #31982

Closed
@Benjamin-Dobell

Description

@Benjamin-Dobell

TypeScript Version: 3.4.0-dev.201xxxxx

Search Terms: Object.assign return type

Code

let test1: string = Object.assign({ a: 1 }, { a: "one" }).a
// $ExpectError
let test2: number = Object.assign({ a: 1 }, { a: "one" }).a // No error
// $ExpectError
Object.assign({ a: 1, b: 2 }, "hi").toLowerCase() // No error
// $ExpectError
Object.assign({ a: 1, b: 2 }, "hi").length // No error

Expected behavior:

Type 'string' is not assignable to type 'number'

Property 'toLowerCase' does not exist on type ...

Property 'length' does not exist on type ...

Actual behavior:

No errors raised.

Playground Link: Link

Related Issues:

Proposal

type IndexerReturnType<T extends ArrayLike<any>> = T extends ArrayLike<infer V> ? V : any;

type ArrayLikeIndexer<T> = T extends ArrayLike<any> ? { [k: number]: IndexerReturnType<T> } : never 

type PickDefined<T> = {
    [P in keyof T]: T[P] extends undefined ? never : T[P]
};

type Assign<A, B> = A extends object ? (
    B extends object ?
        Pick<A, Exclude<keyof A, keyof B>> & PickDefined<B> :
        A & ArrayLikeIndexer<B>
) : (A & B)

declare function assign<A, B>(a: A, b: B): Assign<A, B>

Note 1: PickDefined<T> is necessary with strictNullChecks enabled.
Note 2: In the definition of Assign<A, B> I would have expected the usage of keyof B to need to be replaced with keyof PickDefined<B>. It seems, that's presently not the case - so I've opted to omit it and avoid any potential slow-down. Nonetheless, I must admit that I'm hazy as to why this is permissible.

Obviously to keep things brief I've just covered the single source use-case rather than providing overloads with several source. The definition is nonetheless chainable i.e. Assign<A, Assign<B, C>> etc.

Playground Link: Link (For posterity please enable strictNullChecks)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions