简体   繁体   中英

Is it possible to get the type from a generic, given as parameter

I created a function that takes an object of subscribers, as seen below.

public subscribers = {
    count: <EventEmitter<number>>new EventEmitter<number>(),
    staticCount: <EventEmitter<number>>new EventEmitter<number>()
};

This function waits for both observables to complete, and returns an object with the keys of the object it received, as value the emitted value from the EventEmitter.

type AnyType<T> = {
    [P in keyof T]: any;
}

function ZipObservable<T extends { [name: string]: EventEmitter<any>}>
    (observables: T): Observable<AnyType<T>> {
    const m = CreateMapFromObject(observables);
    const o = new Subject<any>();

    Observable.zip(...Array.from(m.values())).subscribe((res) => {
        const keys = m.keys();
        const c = res.reduce((r, v) => {
            const k = <string>keys.next().value;
            r[k] = v;

            return r
        }, {});

        /**
         *
         */
        o.next(c);
        o.complete();
    });

    return o.asObservable();
}

My current problem is at the type of the value set in the returned object. The object its keys are typed (as you can see in the image).

I also want the type of the value to be set to number (in this case). I created a type; AnyType<T> that's able to set the returned object its keys. Is it possible to also get it to set its value's type?

The type i want it to become, comes from the parameter, which receives a generic; EventEmitter<number> .

Working type safety for the returned object.

截图

So, you want ZipObservable to return an object of type Observable<T> , where the input parameter has the same keys as T but the values for each key K are EventEmitter<T[K]> (where T[K] is the type of the property value of the K key of type T ). That is definitely achievable, through mapped types and inference from mapped types :

First let's define a mapped type which takes every property in T and converts it to an EventEmitter<> of the appropriate type:

type EventEmitters<T> = {
  [K in keyof T]: EventEmitter<T[K]>
}

Now the ZipObservable function signature can be written directly (I will leave the implementation up to you):

declare function ZipObservable<T>(eventEmitters: EventEmitters<T>): Observable<T>; 

And it works because of inference from mapped types:

const ret = ZipObservable(subscribers).subscribe(r => r.count * 3); // no error

Hope that helps; good luck!!

Thanks a lot to @jcalz

You got me on the right path. Your code worked. It removed my type safety though, so i tweaked it a little bit.

-- EDIT

It didn't remove my type safety. My editor just doesn't recognize the keys on the returned object. It does when i use the code below.

type EmittedReturnType<T> = {
    [K in keyof T]: T[K]
}

type EventEmitters<T> = {
    [K in keyof T]: EventEmitter<T[K]>
}

So,

I created two types; First type to be the parameter type. The second type to be the return type.

declare function ZipObservable<T>(observables: EventEmitters<T>): Observable<EmittedReturnType<T>>

Which results in;

A type safe object.

A type safe assign

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