简体   繁体   中英

Using generic types with a class

I'm using Flow and have a use case for generic types but don't know how to use them.

I have a class that takes an array of events of one type. All the event types share some properties (like startTime ) but differ on others. The return value for class functions should be of the same type as the events passed in the constructor array.

To make that more concrete, in the code below I would like to stipulate that if you create an instance of EventUtility with an array of PartyEvent s, then when you ask for EventUtility.earliestEvent() you can be sure you will get a PartyEvent back. (The array passed to the constructor cannot consist of a mixture of objects of different types.)

Thanks.

export class EventUtility {
    // pick item based on JSON-friendly conditional notation
    events: Array<PartyEvent | AppointmentEvent | MealEvent>

    constructor(events: Array<PartyEvent | AppointmentEvent | MealEvent>) {
        this.events = events;
    }

    earliestEvent(): PartyEvent | AppointmentEvent | MealEvent {
        // determine earliest event in array and return it
        return event;
    }
}

What you're looking for is bounded generics. They're explained in the Flow documentation here .

First, make your whole class generic on some type T , not just your individual methods. Then attach a bound (a type annotation) to the type T where it's declared at the top of the class, like this:

class EventUtility<T: PartyEvent | AppointmentEvent | MealEvent> {

Now your class will accept some type T , but only if T matches the bound you've given it. You can only do things to a value of type T internally that are allowed for a value whose type is the type of the bound, and whatever type T is used to create an instance of the class is the same type that will be used for return values.

The second challenge is how to make sure that only one kind of event is stored in your class at the same time. This is challenging, because the type T is a union type, meaning it could be any of the three. Flow will let you instantiate the class with an array of PartyEvent objects, in which case T will have the type PartyEvent , but it will also let you instantiate it with an array of MealEvent and AppointmentEvent objects, in which case T will have the type MealEvent | AppointmentEvent MealEvent | AppointmentEvent . You can get around this by providing an explicit type annotation where you use your EventUtility , stating which type you want it to contain. Even though Flow will let you instantiate EventUtility with a combination of types, it will error if you instantiate it with a larger type than you declare in an explicit annotation.

Here's the solution to your example in the Flow playground. Try creating the class with different bounds for T and uncommenting some of the calls to see what errors pop up. Using { startTime: Date } as the bound for T should give you the same result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM