Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get property of generic type?

I have an abstract class, in the method of which I am passing an item of a generic type. Next, I need to get the property of this item, how to do it correctly?

export abstract class BaseService<T> {
    ...
    public saveItem(item: T) {
        ...
        if (item.id <=== here I got error ) {
        }
        ...
    }

    export class ClusterItem {
        id: number;
        ...
     }

    export class ClustersService extends BaseService<ClusterItem> {
        ...
    }
like image 898
Green176 Avatar asked Sep 07 '17 15:09

Green176


1 Answers

Your code assumes that every type T used with your class may have an id property.

As pointed out by Jon Sharpe in his comment on your question, the correct approach, both in terms of type safety and expressiveness, is to declare this assumption as a type constraint, making it explicit and known to the type checker.

The way to do this is to use the type constraint syntax on your generic type parameter.

For example, you could write

export interface MayHaveId {
  id?: number; // you can use any type, number is just an example
}

export abstract class BaseService<T extends MayHaveId> {
  saveItem(item: T) {
    if (item.id !== undefined) {
      console.log(item.id);
    }
  }
} 

Here we've defined an interface to make the code more readable, but a type literal would work as well.

Note that the id property is declared optional since your logic does not require it to have a value.

If you only intend for the base class to be used with type arguments which do have an id then you should make the property required. This will make the code easier to understand and will catch more errors at compile time by ensuring that it is only used with such types in the first place.

Shahbaaz asked about dynamic properties in a comment.

We can define a type with a dynamic property by using a parametric generic type

type WithProperty<K extends string, V = {}> = {
  [P in K]: V
}

We can consume this type

function withProperty<T, K extends string, V> (x: T, properties: WithProperty<K, V>) {
  return Object.assign(x, properties);
}
like image 170
Aluan Haddad Avatar answered Sep 30 '22 00:09

Aluan Haddad