6

I have a web api that returns the following result

{
  "customerContactID": 1,
  "customerID": 1,
  "firstName": "james",
  "lastName": "smithman",
  "primaryEmail": "james@gmail.comm",
  "primaryPhone": "8788494677",
  "isPrimaryContact": true
}

and I have an angular 5 app that defines an interface as

    interface CustomerContact {
      CustomerContactID: number;
      CustomerID: number;
      FirstName: string;
      LastName: string;
      PrimaryEmail: string;
      PrimaryPhone: string;
      IsPrimaryContact: boolean;
  }

and return the result using

            this.http.get<CustomerContact>(url).subscribe(result => {
            console.log("CustomerContact obtained");
            console.log(result); // prints lowercase properties
            this.customerContact = result;
        }, error => console.error(error));

Unfortunately, when i log the result, I can see that the properties have all been lowercased, so I cannot do something such as

this.currentCustomer = result.CustomerID;

Since it results in undefined. However, I need to be able to set a variable value to the value obtained from the api result, specifically result.CustomerID. Typescript does not allow me to do

this.currentCustomer = result.customerID;

since it results in

TS2551: Property 'customerID' does not exist on type 'CustomerContact'. Did you mean 'CustomerID'?

How do I set the value of a variable to the value of result.customerID despite the compiler [at-loader] error?

I cannot change the API contract at all, also, my typescript interface must have UpperCase for property names.

UPDATE 1 as @pArth savadiya mentioned below, It looks like I can do this use any type

Although, Im not sure if the repercussions, if any

I dont believe this is a duplicate of Convert returned JSON Object Properties to (lower first) camelCase since that question has a result model that has uppercase properties, which is not what I have here.

UPDATE 2 After some close observation ,I realized that the big issue here was the MISTMATCH between the api response property casing and the angular/typescript casing mismatch. Without them being the same, it causes issues and forces odd workarounds. The solution simply was to match the interface casing with the response casing for this particular request. Its that simple. Thank you everyone.

Judy007
  • 5,484
  • 4
  • 46
  • 68
  • " my typescript interface must have UpperCase for property names." - Why? Typescript is to help you, and you need to match it with the result you get – Ziv Weissman Jun 04 '18 at 05:30
  • Hi @ZivWeissman, I appreciate the question. The short answer is that if I change 1 property just to overcome this one case, then it breaks the naming convention. The naming convention is UpperCase for property names. Can I change it? Sure, but what are my other options here? Having a conventions keeps things predictable. – Judy007 Jun 04 '18 at 05:37
  • If you must use it this way, and you want to use interface then I suggest you build a helper generic function that takes and param1:any, use some PascalCase Converter and output your interface object. – Ziv Weissman Jun 04 '18 at 05:48
  • you can try like this: this.currentCustomer = result["customerID"]; – Parth Savadiya Jun 04 '18 at 05:57
  • 1
    There are so many conflicting conventions in development, it's important to separate those that are just because, from those with functional purpose. In your case, the service outputs fields in uppercase, but for some reason you want javascript to break it's own convention and make the interface case insensitive, so that you can have lowercase member variables. I recommend following the service binding or you will end up writing a converter for everything and defeating the purpose of the framework to begin with. – Dan Chase Jun 04 '18 at 05:59
  • separate conventions that are just because from those with a functional purpose? I dont believe anyone reading your code for the first time would be able to understand that separation. Thats the purpose of a convention. Also, I dont think there MUST be conflicting conventions during development, that sounds like a personal preference rather than a rule. – Judy007 Jun 04 '18 at 06:12
  • Possible duplicate of [Convert returned JSON Object Properties to (lower first) camelCase](https://stackoverflow.com/questions/12931828/convert-returned-json-object-properties-to-lower-first-camelcase) – Oliver Jun 04 '18 at 06:19
  • @joey if you are removing the and using - it is like you are not using typescript at all. As I said before, typescript is made to help you, you don't have to use it. – Ziv Weissman Jun 04 '18 at 06:23
  • @ZivWeissman, so if I understand you correctly, you are saying that we can opt in to take advantage of TS, but if we need to "relax" things a bit, ,thats okay too, correct? – Judy007 Jun 04 '18 at 06:29
  • @joey yes pretty much. – Ziv Weissman Jun 04 '18 at 06:54
  • after more observation, it seems prudent to have the typescript interface property name casing match that of the api result properties.. – Judy007 Jun 04 '18 at 07:05

3 Answers3

1

In your code you tightly coupled HTTP response result with your typescript interface(CustomerContact) use instead of it.

this.http.get <any> (url).subscribe(result => {
  console.log("CustomerContact obtained");
  console.log(result); // prints lowercase properties
  this.customerContact = result;
}, error => console.error(error));

then you can able to write this.currentCustomerID = result.customerID;

or you can try like this: this.currentCustomer = result["customerID"];

Parth Savadiya
  • 1,203
  • 3
  • 18
  • 40
  • This works, although I have to ask, what are the drawbacks of using here? my understanding was that the coupling is a good thing to avoid issues that were present in angularJS, thats the purpose of typescript anyways, right? type safety. – Judy007 Jun 04 '18 at 05:45
  • updated my question to include this , thank you. I suppose I will have to give up type safety in this situation then? – Judy007 Jun 04 '18 at 05:51
0

In comparison with JavaScript, TypeScript helps to make explicit choices about types i.e. about the design of the code. Your question is indeed a matter of design decisions of your Angular application.

It helps to reason considering layers in the architecture: the WebApi, the service fetching its data and the UI components are not in the same layers.

You can decide to have for the “CustomerContact”:

  1. The same type in all layers:
    • This type is defined by the WebApi so all fields are in camelCase: interface CustomerContact { customerContactID: number… } and you can do http.get<CustomerContact>(url).
    • It’s cheap in the short term but expensive in the long run because any change in the WebApi signature can induce a lots of changes in several files in all layers!
  2. Distinct types:
    • The WebApi method returns a DTO: interface CustomerContactDto { customerContactID: number… } and http.get<CustomerContactDto>(url). Don’t use the type any if you want to keep the type safety provided with TypeScript.
    • The domain layer deals with a CustomerContact with whatever fields you likes, in whatever case you wants (camelCase, PascalCase, …) even if PascalCase in more a C# convention than a TypeScript one.
    • The service containing the http.get<CustomerContactDto>(url) will do the mapping between both types to return a CustomerContact, as part of an ACL. This mapping can be done simply field by field: const customerContact = new CustomerContact(); customerContact.CustomerContactID = result.customerContactID; ….
Romain Deneau
  • 2,841
  • 12
  • 24
-4

In your interface change

CustomerID: number;

to

customerID: number;

It will work as you expect.