0

I have created model(by interface) for my json response:

export interface Test {
    id: number;
    name: string;
}

and I have variable for data:

  public test: Test;

But when I get json response with more parameters like last_name which is not in interface I still can use it in code. How can I cast this json response to match only my model?

I tried assertion but It's not working, I still have access to all other properties.

5
  • You should copy only specified properties to the variable from json response Commented Feb 24, 2018 at 12:10
  • Possible duplicate of Learning TypeScript - Casting Types Commented Feb 24, 2018 at 12:11
  • But when I have for example 20 properties and response have 40, it would be hard to write it manually. Commented Feb 24, 2018 at 12:12
  • maybe you could iterate over the properties of the interface and only assign these, see stackoverflow.com/questions/41959488/… Commented Feb 24, 2018 at 12:28
  • but it doesn't make sense, so how should I make a model for my json response? Commented Feb 24, 2018 at 12:35

2 Answers 2

1

Interfaces are known only at compile time. You can use classes instead and by declaring properties in constructor they will be known at runtime:

class Test {
  constructor(
    public id: number,
    public name: string
  ){}
}

Then you can create function that will return an instance of a given class and fill it with data:

function cast<T>(data: any, model: new (...args: any[]) => T ): T {
  const classInstance = new model();
  const classProps = Object.getOwnPropertyNames(classInstance);

  classProps.forEach(prop => classInstance[prop] = data[prop]);
  return classInstance;
}

You can use this function to map received data to given model:

this.http.get<Test>('someUrl').map(res => cast(res, Test))
Sign up to request clarification or add additional context in comments.

Comments

0

I couldn't do it for an Interface, but using a class to achieve what you want to do, is possible.

Angular [Typescript]

class Award {
  name = "";
  category = "";
}

this.httpClient.get<Awards>("./assets/configs/award.json").subscribe(($:Award) => {
  // Pass an instance of the Class, you wish to receive your response as
  console.log(this.takeWhatIsNecessary(new Award(), $));
});

// Breadth First Search
// This function will go through keys, in any depth, and copy
// property values from corresponding keys from Response
// Into the target value
// And returns the target
takeWhatIsNecessary(target, response) {
const stack = [];

if (!response || !target) {
  return response;
}

stack.push({
  r: response,
  t: target
});

while (stack.length > 0) {
   const obj = stack.shift();

   for (const key in obj.t) {
     if (obj.t.hasOwnProperty(key) && obj.r.hasOwnProperty(key)) {
       if (typeof obj.t[key] === "object") {
         stack.push({
           t: obj.t[key],
           r: obj.r[key]
         });
       }
       obj.t[key] = obj.r[key];
     }
   }
 }
 return target;
}

Javascript Sample

var uglyJSON = '{"name":"Test Name","category":"Test Category","author":"Do Not","appendix":"Read This","important":{"take_this":"Awesome","not_this":"Wow"}}';

var uglyResponse = JSON.parse(uglyJSON);

var myCustomClassObj = {
  name: "",
  category: "",
  important: {
    take_this: ""
  }
};

console.log(takeWhatIsNecessary(myCustomClassObj, uglyResponse));

// Breadth First Search
function takeWhatIsNecessary(target, response) {
  var stack = [];

  if (!response || !target) {
    return response;
  }

  stack.push({
    r: response,
    t: target
  });

  while (stack.length > 0) {
    var obj = stack.shift();

    for (var key in obj.t) {
      if (obj.t.hasOwnProperty(key) && obj.r.hasOwnProperty(key)) {
        if (typeof obj.t[key] === "object") {
          stack.push({
            t: obj.t[key],
            r: obj.r[key]
          });
          continue;
        }
        obj.t[key] = obj.r[key];
      }
    }
  }

  return target;
}

1 Comment

This will work with response of any depth i.e of any amount of nesting. var a = { x: 23, y: { p: 234 } };

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.