Typescript generics for array

I need to extend a generic list of Array which has been extended from my class. How to do it properly?

export interface DeliveryMethod {
  readonly id: string;
  readonly company: string;
  readonly cost: number;
  readonly threshold: number;
  readonly intervals: Array<Interval>;
  readonly paymentMethods: Array<PaymentMethod>;
}

export interface Delivery {
  selected: SelectedDelivery;
  available: { [key : string] : Array<T extends DeliveryMethod>};
}

Cannot find name 'T'.ts(2304)

available: { [key : string] : Array<T extends DeliveryMethod>};

For example i need something like that:

const Delivery = {
   selected :{/*data inside*/},
   available:{
      pickup: [<Pickup>{},<Pickup>{}],
      courier: [<Courier>{},<Courier>{}]  
   }
}

Upvotes: 5

Views: 6237

Answers (2)

Christian Vincenzo Traina
Christian Vincenzo Traina

Reputation: 10374

The @aopanasenko answer is fine. I want to complete it adding a way to solve the problem of multiple specifications.

If the properties of available aren't much, and they're fixed and stable, then you could think about listing them all in the Delivery interface:

interface Delivery<T extends DeliveryMethod, U extends DeliveryMethod> {
  available: { [key : string] : Array<T | U>};
};

Then you can define the delivery object like this:

const delivery: Delivery<Pickup, Courier>

If you don't know the properties a priori, then you need a way to link a property name to a TypeScript type, for example I added an available object just for the mapping:

interface Delivery {
  available: { [key: string]: Array<DeliveryMethod> | null };
};

const delivery: Delivery = {
  available: {}
}

const available: {
  pickup: Pickup[] | null,
  courier: Courier[] | null
} = {
  pickup: null,
  courier: null
};

delivery.available = { ...delivery.available, ...available };

In this way, it's correctly type-checked. I also added | null in order to provide an example, you can remove it.

Upvotes: 3

aopanasenko
aopanasenko

Reputation: 478

Update

As mentioned by @AndreaSimoneCosta in comment the following code should work:

export interface DeliveryMethod {
  readonly id: string;
  readonly company: string;
  readonly cost: number;
  readonly threshold: number;
  readonly intervals: Array<Interval>;
  readonly paymentMethods: Array<PaymentMethod>;
};

export interface Delivery<T extends DeliveryMethod = DeliveryMethod> {
  selected: SelectedDelivery;
  available: { 
    [key : string] : Array<T>
  };
};

You should define generic type parameter list in angle brackets following the name of the Delivery interface:

export interface DeliveryMethod {
  readonly id: string;
  readonly company: string;
  readonly cost: number;
  readonly threshold: number;
  readonly intervals: Array<Interval>;
  readonly paymentMethods: Array<PaymentMethod>;
};

export interface Delivery<T extends DeliveryMethod> {
  selected: SelectedDelivery;
  available: { 
    [key : string] : Array<T>
  };
};

Upvotes: 0

Related Questions