5

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>{}]  
   }
}
5
  • 2
    export interface Delivery<T> - you need to declare your generic parameter. Commented Apr 14, 2020 at 5:15
  • @VLAZ its not working for my example. Commented Apr 14, 2020 at 5:24
  • 2
    Because I just wrote it too short, I suppose. I was trying to save space, I guess. export interface Delivery<T extends DeliveryMethod> - you should declare the generic parameter with its constraints as part of the interface declaration (or method/function declaration for a generic version of that when you have it). Once you've declared the parameter, you can then just use it within your interface as just the generic parameter name: available: { [key : string] : Array<T>};. Commented Apr 14, 2020 at 5:31
  • Could you not just have Array<DeliveryMethod>? I'm guessing anything that extends it would also work? Commented Apr 14, 2020 at 7:10
  • Do you really need a different type for Pickup and Courier? Commented Apr 14, 2020 at 7:20

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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>
  };
};

9 Comments

But then he isn't able to have different types inside different arrays, as happens in his last example
@AndreaSimoneCosta, think types Courier and Pickup have the same structure with DeliveryMethod .
And if you do like these, you could mix the types :( typescriptlang.org/play/#code/…
@AndreaSimoneCosta, thanks for pointing out inaccuracies in my answer. I updated an answer with link to your comment.
@Иван Яковлев T extends DeliveryMethod = DeliveryMethod means that T should be assignable to DeliveryMethod and, if you don't provide a T, `DeliveryMethod' will be used as default type value.
|

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.