Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a property to an existing object to satisfy an interface in typescript?

Tags:

typescript

Here's what I would like to do in a nutshell:

interface A {
     prop1: string;
}

interface B extends A {
    prop2: string;
}

someImportantFunction(x: A): B {
    var ret: B = x.prop2 = someCalculation(); //Error, but if possible x would now satisfy B

    return ret;
}

The english version of my question is: how can I add new properties to an existing object in typescript, with the goal of satisfying a more-derived interface definition? Perhaps this is not possible, or I am missing some obvious approach.

UPDATE: Also, suppose the list of properties on interface A is long, so boilerplate assignment by mapping properties is laborious and not clean.

I also see something like this would work, but it seems like a hack:

someImportantFunction(x: A): B {
    var ret: B = <B>x;
    ret.prop2 = someCalculation();

    return ret;
}

Thanks, Mathias

like image 631
mathias999us Avatar asked Dec 28 '15 13:12

mathias999us


People also ask

How do I add a property in TypeScript?

To add a property to an object in TypeScript, set the property as optional on the interface you assign to the object using a question mark. You can then add the property at a later point in time without getting a type error. Copied!

How do you assign a value to an object in TypeScript?

To use the Object. assign() method in TypeScript, pass a target object as the first parameter to the method and one or more source objects, e.g. const result = Object. assign({}, obj1, obj2) . The method will copy the properties from the source objects to the target object.

How do you add a property to an object?

One way is to add a property using the dot notation: obj. foo = 1; We added the foo property to the obj object above with value 1.

How do you create an interface in TypeScript for an object?

To create an object based on an interface, declare the object's type to be the interface, e.g. const obj1: Employee = {} . The object has to conform to the property names and the type of the values in the interface, otherwise the type checker throws an error.


2 Answers

Use Object.assign:

interface A { prop1: string; }
interface B extends A { prop2: string; }

someImportantFunction(x: A): B {
    var ret: B = Object.assign(x, { prop2 : someCalculation()});

    return ret;
}

The types come out because of the typing file defines the return values as an intersection type (&):

assign<T, U>(target: T, source: U): T & U;
like image 153
Fowl Avatar answered Oct 17 '22 05:10

Fowl


With intersection types (TS 1.6+), you can have more type safety:

// your typical mixin function, like lodash extend or jQuery.extend
// you can use one of those instead of this quick and dirty implementation,
// the main reason for having this function is its type signature
function extend<T1, T2>(source: T1, addition: T2): T1 & T2 {
  let result = <T1 & T2>source;
  for(let key of Object.keys(addition)) {
    result[key] = addition[key];
  }
  return result;
}

interface A {
  prop1: string;
}

interface B extends A {
  prop2: string;
}

function someImportantFunction(x: A): B {
  return extend(x, {
    prop2: someCalculation()
  });
}

This way the compiler can determine what properties of type B are missing from type A and ensure your extend call provides them.

like image 6
DCoder Avatar answered Oct 17 '22 05:10

DCoder