Permalink
Browse files

fix(types): Constrain ActionsObservable type param (#289)

By making the type parameter `T` extend `Action` (i.e. telling the compiler that `T <: { type: string }`),
it's possible to type `ofType()` correctly using lookup types.
  • Loading branch information...
pelotom authored and jayphelps committed Aug 15, 2017
1 parent 91ad1ca commit 2144e7d46a912d4175fe6c5b0ea2263b9dc4e8a6
Showing with 20 additions and 20 deletions.
  1. +18 −18 index.d.ts
  2. +2 −2 test/typings.ts
@@ -1,38 +1,38 @@
import { Middleware, MiddlewareAPI } from 'redux';
import { Middleware, MiddlewareAPI, Action } from 'redux';
import { Observable, ObservableInput } from 'rxjs/Observable';
import { Scheduler } from 'rxjs/Scheduler';
import { Operator } from 'rxjs/Operator';

export declare class ActionsObservable<T> extends Observable<T> {
export declare class ActionsObservable<T extends Action> extends Observable<T> {
/**
* Just like RxJS itself, we can't actually make this method always type-safe
* because we would need non-final position spread params e.g.
* `static of<T>(...items: T, scheduler?: Scheduler): ActionsObservable<T>`
* which isn't possible in either JavaScript or TypeScript. So instead, we
* provide safe typing for up to 6 items, following by a scheduler.
*/
static of<T>(item1: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T>(item1: T, item2: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T>(item1: T, item2: T, item3: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T>(item1: T, item2: T, item3: T, item4: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T>(item1: T, item2: T, item3: T, item4: T, item5: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T>(item1: T, item2: T, item3: T, item4: T, item5: T, item6: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T>(...array: Array<T | Scheduler>): ActionsObservable<T>;
static of<T extends Action>(item1: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T extends Action>(item1: T, item2: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T extends Action>(item1: T, item2: T, item3: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T extends Action>(item1: T, item2: T, item3: T, item4: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T extends Action>(item1: T, item2: T, item3: T, item4: T, item5: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T extends Action>(item1: T, item2: T, item3: T, item4: T, item5: T, item6: T, scheduler?: Scheduler): ActionsObservable<T>;
static of<T extends Action>(...array: Array<T | Scheduler>): ActionsObservable<T>;

static from<T>(ish: ObservableInput<T>, scheduler?: Scheduler): ActionsObservable<T>;
static from<T, R>(ish: ArrayLike<T>, scheduler?: Scheduler): ActionsObservable<R>;
static from<T extends Action>(ish: ObservableInput<T>, scheduler?: Scheduler): ActionsObservable<T>;
static from<T extends Action, R extends Action>(ish: ArrayLike<T>, scheduler?: Scheduler): ActionsObservable<R>;

constructor(input$: Observable<T>);
lift<R>(operator: Operator<T, R>): ActionsObservable<R>;
ofType(...key: string[]): ActionsObservable<T>;
ofType(...key: any[]): ActionsObservable<T>;
lift<R extends Action>(operator: Operator<T, R>): ActionsObservable<R>;
lift<R>(operator: Operator<T, R>): Observable<R>;
ofType(...key: T['type'][]): ActionsObservable<T>;
}

export declare interface Epic<T, S, D = any> {
export declare interface Epic<T extends Action, S, D = any> {
(action$: ActionsObservable<T>, store: MiddlewareAPI<S>, dependencies: D): Observable<T>;
}

export interface EpicMiddleware<T, S, D = any> extends Middleware {
export interface EpicMiddleware<T extends Action, S, D = any> extends Middleware {
replaceEpic(nextEpic: Epic<T, S, D>): void;
}

@@ -46,7 +46,7 @@ interface Options<D = any> {
dependencies?: D;
}

export declare function createEpicMiddleware<T, S, D = any>(rootEpic: Epic<T, S, D>, options?: Options<D>): EpicMiddleware<T, S, D>;
export declare function createEpicMiddleware<T extends Action, S, D = any>(rootEpic: Epic<T, S, D>, options?: Options<D>): EpicMiddleware<T, S, D>;

export declare function combineEpics<T, S, D = any>(...epics: Epic<T, S, D>[]): Epic<T, S, D>;
export declare function combineEpics<T extends Action, S, D = any>(...epics: Epic<T, S, D>[]): Epic<T, S, D>;
export declare function combineEpics<E>(...epics: E[]): E;
@@ -1,5 +1,5 @@
import { expect } from 'chai';
import { createStore, applyMiddleware, MiddlewareAPI } from 'redux';
import { createStore, applyMiddleware, MiddlewareAPI, Action } from 'redux';
import { Observable } from 'rxjs/Observable';
import { ajax } from 'rxjs/observable/dom/ajax';
import { asap } from 'rxjs/scheduler/asap';
@@ -80,7 +80,7 @@ const dependencies: Dependencies = {
const epicMiddleware1: EpicMiddleware<FluxStandardAction, State> = createEpicMiddleware<FluxStandardAction, State>(rootEpic1, { dependencies });
const epicMiddleware2 = createEpicMiddleware(rootEpic2, { dependencies });

interface CustomEpic<T, S, U> {
interface CustomEpic<T extends Action, S, U> {
(action$: ActionsObservable<T>, store: MiddlewareAPI<S>, api: U): Observable<T>;
}

0 comments on commit 2144e7d

Please sign in to comment.