Jukka Varis Jukka Varis - 1 year ago 119
TypeScript Question

How to extend anonymous type in Typescript

When chaining functionality in

with anonymous types for example like this:

let array = [{ seed: 2 }, { seed: 3 }];
.map(i => ({ seed: i.seed, square: i.seed * i.seed }))
.forEach(i => console.log(`square for ${i.seed} is ${i.square}`));

I need to define new anonymous type for map function. If I would have multiple steps all producing new properties, I'd end up writing lots of definition code to get all properties carried over.
I could use
), but that way I'll lose intellisense and strong typing.

.map(i => $.extend(i, { square: i.seed * i.seed }))
.forEach(i => console.log(`square for ${i.seed} is ${i.square}`));

How can I extend anonymous object without defining all properties again while keeping strong typing?

Answer Source

I have finally found a solution. This can be achieved by Intersection Types. Those can be used with anonymous types and classes. In the example below, extend function will copy properties from each of objects and return an object of Intersection Type. This will reduce considerable amount of type definition code without losing intellisense and strong typing.

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
    return result;

let array = [{ seed: 2 }, { seed: 3 }];

    .map(i => extend(i, { square: i.seed * i.seed }))
    .map(i => extend(i, { cube: i.square * i.seed }))
    .forEach(i => console.log(`square for ${i.seed} is ${i.square} and cube is ${i.cube}`));

Same in Playground

This is implemented f.e. in core-js and its type definitions return Intersection Type:

assign<T, U>(target: T, source: U): T & U;
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download