Open
Description
In JavaScript is possible to mutate objects inside functions. Right now, the following code in JavaScript:
function merge(x,y) {
Object.assign(x,y);
}
let x = {a: 1};
merge(x, {b: 2});
console.log(x.b);
Can't be written in TypeScript without casting the type. There are a few options whose type definition is wrong in all scenarios I can think of (maybe I'm missing a better option):
Option 1
let x: {a: number, b: number} = {a: 1}; // Error, missing b
merge(x, {b: 2});
Option 2
let x: {a: number, b: number} = {a: 1, b: 2};
merge(x, {b: null});
// From here, x.b is not a number anymore, but you could do
let y: number= x.b;
Suggestion
There could be an extension to function parameter definition like the following:
// then keyword indicates that before it can be type A, and after it will be of type A&B.
function merge<A,B>(x: A then x2: A&B, y: B) {
Object.assign(x2,y);
}
let x: {a: number, b: number} = {a: 1, b: 2};
merge(x, {b: null});
// Here, type of x is {a: number, b: number} & {b: null}
x.b; // Type null
There, we indicate that whatever type was x before, now it is something different. The code above could be written in TypeScript as follows:
// then keyword indicates that before it can be type A, and after it will be of type A&B.
function merge<A,B>(x: A, y: B) {
Object.assign(x,y);
}
let x: {a: number, b: number} = {a: 1, b: 2};
merge(x, {b: null});
// Here, type of x is {a: number, b: number} & {b: null}
let xAfterMerge = x as {a: number, b: number} & {b: null};
// Since this line, x should not be used but xAfterMerge
xAfterMerge.b; // Type null
Another example
interface Before {
address: string;
}
interface After {
addr: string;
}
function map(userb: Before then usera: After) {
usera.addr = userb.address;
delete userb.address;
}
let u = {adress: "my street"};
map(u);
console.log(u.addr);
That could be syntax sugar for this:
interface Before {
address: string;
}
interface After {
addr: string;
}
function map(userb: any) {
userb.addr = userb.address;
delete userb.address;
}
let u = {adress: "my street"};
map(u);
console.log((u as After).addr);
Syntax
It could be something like:
identifier: type *then* identifier: type
With the identifiers being different, and with the types being mandatory an extension of Object.