Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe typing of Object.assign

Tags:

typescript

We're looking for a type safe way of using Object.assign. However, we can't seem to make it work.

To show our problem I'll use the copyFields method from the Generics documentation

function copyFields<T extends U, U>(target: T, source: U): T {
    for (let id in source) {
        target[id] = source[id];
    }
    return target;
}

function makesrc(): Source { return {b: 1, c: "a"}}

interface Source {
    a?: "a"|"b",
    b: number,
    c: "a" | "b"
}

I want the engine to prevent me from creating undeclared properties

/*1*/copyFields(makesrc(), {d: "d"}); //gives an error
/*2*/copyFields(makesrc(), {a: "d"}); //gives an error
/*3*/copyFields(makesrc(), {c: "d"}); //should give an error, but doesn't because "a"|"b" is a valid subtype of string.

//I don't want to specify all the source properties 
/*4*/copyFields(makesrc(), {b: 2}); //will not give me an error
/*5*/copyFields(makesrc(), {a: "b"}); //should not give an error, but does because string? is not a valid subtype of string 

We have attempted to solve this with explicitly providing the types to the copyfields call but we can't find a call that will make all examples work.

For example: to make 5 work you might call copyFields like this:

/*5'*/copyFields<Source,{a?:"a"|"b"}>(makesrc(), {a: "b"}); 

but subsequent changes to the Source type (such as removing the "b" option) will now no longer result in a type error

Does anyone know of a way to make this work?

like image 333
renevanderark Avatar asked Oct 30 '22 21:10

renevanderark


1 Answers

You can use Object.assign<TargetType, SourceType>(target, source) - I think it provides type safety.

like image 78
evgeni tsvetanov Avatar answered Jan 02 '23 19:01

evgeni tsvetanov