#Making Object Assign Type Safe?

12 messages · Page 1 of 1 (latest)

sudden elk
#

Hey there, currently Object.assign has multiple overloads. Does know of a way we can take any number of arguments to assign and actually take the types that are being passed and merge it to the first one?
Currently, it either takes 3 arguments that are typed, or it will take an array of any

thin rampart
#

I think it'll always return an intersection type of the arguments

#

but you could probably cast it to be one type with as

mystic wave
#

@sudden elk Maybe you can give an example of what you mean, exactly?

static steeple
#

my guess is they don't want this inference to happen:

terse wrenBOT
#
const bad = Object.assign({}, { a: 1 }, { b: 2 }, { c: 3 }, { d: 4 })
//    ^? - const bad: any
static steeple
#

i came up with this, but i'm sure it could be simplified:

terse wrenBOT
#
type Assigned<Args extends readonly [{}, ...{}[]], Merged = {}> =
    Args extends [infer Head] ? Merged & Head
    : Args extends [infer Head, ...infer Rest extends readonly [{}, ...{}[]]] ? Assigned<Rest, Merged & Head>
    : never

declare const objectAssign: <Args extends readonly [{}, ...{}[]]>(...args: Args) => Assigned<Args>

const bad = Object.assign({}, { a: 1 }, { b: 2 }, { c: 3 }, { d: 4 })
//    ^? - const bad: any
const good = objectAssign({ a: 1 }, { b: 2 }, { c: 3 }, { d: 4 })
//    ^? - const good: {
//        a: number;
//    } & {
//        b: number;
//    } & {
//        c: number;
//    } & {
//        d: number;
//    }
static steeple
#

personally i usually use spreads for this ({ ...a, ...b })

mystic wave
#

Ah, yeah, didn't realize that only went up to three objects. I might just throw a few more overloads into a .d.ts file if necessary:

// Support merging up to six objects into the target
interface ObjectConstructor {
    assign<T extends {}, U, V, W, X>(target: T, source1: U, source2: V, source3: W, source4: X): T & U & V & W & X;
    assign<T extends {}, U, V, W, X, Y>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y): T & U & V & W & X & Y;
    assign<T extends {}, U, V, W, X, Y, Z>(target: T, source1: U, source2: V, source3: W, source4: X, source5: Y, source6: Z): T & U & V & W & X & Y & Z;
}
#

Could also theoretically just split it into multiple assigns. (But yeah, spread seems cleaner, too)

sudden elk
#

i found a solution, prettu similar to @static steeple