Recreated types for flux@3.2 (#15800)

* Recreated types for flux@3.1.2.

* Added backward compatibility with implementation. Added overload for create method.

* Fixed tslint error in tests.

* Added one more test for old implementation.

* Added more gerenrics in create method. Updated tests.

* Fixed errors.

* Typescript version changed to 2.2.

* Updated `createFunctional` return.
This commit is contained in:
Giedrius Grabauskas
2017-05-05 04:04:37 +03:00
committed by Mohamed Hegazy
parent 9fbba5a517
commit 39cf359166
13 changed files with 433 additions and 338 deletions

View File

@@ -1,126 +0,0 @@
import flux = require('flux')
import FluxUtils = require('flux/utils')
import React = require('react')
var Component = React.Component
var Container = FluxUtils.Container
//
// Basic dispatcher usage
//
var basicDispatcher = new flux.Dispatcher<any>()
// register(callback: (payload: any) => void): string
var id: string = basicDispatcher.register((payload) => {
// payload is type: any
payload.anything
})
// unregister(id: string): void
basicDispatcher.unregister(id)
// waitFor(ids: string[]): void
basicDispatcher.waitFor([id])
// dispatch(payload: any): void
basicDispatcher.dispatch({ msg: 'hello' })
// isDispatching(): boolean
var dispatcherIsDispatching: boolean = basicDispatcher.isDispatching()
//
// Typed payload
//
enum ActionSource { Server, View }
enum ActionType { Create, Update, Delete }
interface Action {
source: ActionSource
type: ActionType
data: Object
}
var typedDispatcher = new flux.Dispatcher<Action>()
var typedPayload: Action
var typedStore = {
dispatcherID: typedDispatcher.register((payload) => {
typedPayload = payload
})
}
typedDispatcher.dispatch(typedPayload)
//
// Derived dispatcher
//
class CustomDispatcher extends flux.Dispatcher<Action> {
// Dispatch an action with server as source
handleServerAction(type: ActionType, data: Object) {
this.dispatch({
source: ActionSource.Server,
type: type,
data: data,
})
}
// Dispatch an action with view as source
handleViewAction(type: ActionType, data: Object) {
this.dispatch({
source: ActionSource.View,
type: type,
data: data,
})
}
}
var customDispatcher = new CustomDispatcher()
export = customDispatcher
// Sample Reduce Store
class CounterStore extends FluxUtils.ReduceStore<number, any> {
getInitialState(): number {
return 0;
}
reduce(state: number, action: any): number {
switch (action.type) {
case 'increment':
return state + 1;
case 'square':
return state * state;
default:
return state;
}
}
}
const Store = new CounterStore(basicDispatcher);
// Sample Flux container with CounterStore
class CounterContainer extends Component<any, any> {
static getStores() {
return [Store];
}
static calculateState(prevState: any) {
return {
counter: Store.getState(),
};
}
render() {
return this.state.counter;
}
}
const container = Container.create(CounterContainer);

73
types/flux/index.d.ts vendored
View File

@@ -1,69 +1,12 @@
// Type definitions for Flux 3.0
// Type definitions for Flux 3.1
// Project: http://facebook.github.io/flux/
// Definitions by: Steve Baker <https://github.com/stkb/>, Giedrius Grabauskas <https://github.com/GiedriusGrabauskas/>
// Definitions by: Steve Baker <https://github.com/stkb/>
// Giedrius Grabauskas <https://github.com/GiedriusGrabauskas/>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.1
// TypeScript Version: 2.2
/// <reference types="react" />
/// <reference types="fbemitter" />
import * as Dispatcher from "./lib/Dispatcher";
export = Flux;
declare namespace Flux {
/**
* Dispatcher class
* Create an instance to use throughout the application.
* Or extend it to create a derived dispatcher class.
*
* Specify a type in the 'TPayload' generic argument to use strongly-typed payloads,
* otherwise specify 'any'
*
* Examples:
* var dispatcher = new flux.Dispatcher<any>()
* var typedDispatcher = new flux.Dispatcher<MyCustomActionType>()
* class DerivedDispatcher extends flux.Dispatcher<MyCustomActionType> { }
*/
export class Dispatcher<TPayload> {
/**
* Create an instance of the Dispatcher class to use throughout the application.
*
* Specify a type in the 'TPayload' generic argument to use strongly-typed payloads,
* otherwise specify 'any'
*
* Examples:
* var dispatcher = new flux.Dispatcher<any>()
* var typedDispatcher = new flux.Dispatcher<MyCustomActionType>()
*/
constructor();
/**
* Registers a callback that will be invoked with every payload sent to the dispatcher.
* Returns a string token to identify the callback to be used with waitFor() or unregister.
*/
register(callback: (payload: TPayload) => void): string;
/**
* Unregisters a callback with the given ID token
*/
unregister(id: string): void;
/**
* Waits for the callbacks with the specified IDs to be invoked before continuing execution
* of the current callback. This method should only be used by a callback in response
* to a dispatched payload.
*/
waitFor(IDs: string[]): void;
/**
* Dispatches a payload to all registered callbacks
*/
dispatch(payload: TPayload): void;
/**
* Gets whether the dispatcher is currently dispatching
*/
isDispatching(): boolean;
}
}
export {
Dispatcher
};

45
types/flux/lib/Dispatcher.d.ts vendored Normal file
View File

@@ -0,0 +1,45 @@
declare namespace Dispatcher { }
declare class Dispatcher<TPayload> {
/**
* Create an instance of the Dispatcher class to use throughout the application.
*
* Specify a type in the 'TPayload' generic argument to use strongly-typed payloads,
* otherwise specify 'any'
*
* Examples:
* var dispatcher = new flux.Dispatcher<any>()
* var typedDispatcher = new flux.Dispatcher<MyCustomActionType>()
*/
constructor();
/**
* Registers a callback that will be invoked with every payload sent to the dispatcher.
* Returns a string token to identify the callback to be used with waitFor() or unregister.
*/
register(callback: (payload: TPayload) => void): string;
/**
* Unregisters a callback with the given ID token
*/
unregister(id: string): void;
/**
* Waits for the callbacks with the specified IDs to be invoked before continuing execution
* of the current callback. This method should only be used by a callback in response
* to a dispatched payload.
*/
waitFor(IDs: string[]): void;
/**
* Dispatches a payload to all registered callbacks
*/
dispatch(payload: TPayload): void;
/**
* Gets whether the dispatcher is currently dispatching
*/
isDispatching(): boolean;
}
export = Dispatcher;

65
types/flux/lib/FluxContainer.d.ts vendored Normal file
View File

@@ -0,0 +1,65 @@
import * as Dispatcher from "./Dispatcher";
import * as FluxStore from "./FluxStore";
import * as React from "react";
/**
* A FluxContainer is used to subscribe a react component to multiple stores.
* The stores that are used must be returned from a static `getStores()` method.
*
* The component receives information from the stores via state. The state
* is generated using a static `calculateState()` method that each container must implement.
*/
/**
* Default options to create a Container.
*
* @interface RealOptions
*/
export interface RealOptions {
/**
* Default value: true
*
* @type {boolean}
*/
pure?: boolean;
/**
* Default value: false
*
* @type {boolean}
*/
withProps?: boolean;
/**
* Default value: false
*
* @type {boolean}
*/
withContext?: boolean;
}
export type ComponentConstructor<TProps> = React.ComponentClass<TProps> | React.StatelessComponent<TProps>;
export interface ComponentStatic<TProps, TState, TContext> {
getStores(maybeProps?: TProps, maybeContext?: TContext): Array<FluxStore<any>>;
calculateState(prevState: TState, maybeProps?: TProps, maybeContext?: TContext): TState;
}
export type Component<TProps, TState, TContext> = ComponentConstructor<TProps> & ComponentStatic<TProps, TState, TContext>;
/**
* Create is used to transform a react class into a container
* that updates its state when relevant stores change.
* The provided base class must have static methods getStores() and calculateState().
*/
export function create<TProps>(base: Component<TProps, any, any>, options?: RealOptions): Component<TProps, any, any>;
export function create<TProps, TState>(base: Component<TProps, TState, any>, options?: RealOptions): Component<TProps, TState, any>;
export function create<TProps, TState, TContext>(base: Component<TProps, TState, TContext>, options?: RealOptions): Component<TProps, TState, TContext>;
export function create<TProps, TState, TContext, TStatic>(base: Component<TProps, TState, TContext> & TStatic, options?: RealOptions): Component<TProps, TState, TContext> & TStatic;
/**
* This is a way to connect stores to a functional stateless view.
*/
export function createFunctional<TProps, TState>(
viewFn: (props: TProps) => React.ReactElement<TState>,
getStores: (maybeProps?: TProps, maybeContext?: any) => Array<FluxStore<any>>,
calculateState: (prevState?: TState, maybeProps?: TProps, maybeContext?: any) => TState,
options?: RealOptions
): Component<TProps, TState, any>;

26
types/flux/lib/FluxMixinLegacy.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
import * as FluxStore from "./FluxStore";
declare namespace FluxMixinLegacy {
interface Options {
withProps?: boolean;
}
}
/**
* `FluxContainer` should be preferred over this mixin, but it requires using
* react with classes. So this mixin is provided where it is not yet possible
* to convert a container to be a class.
*
* This mixin should be used for React components that have state based purely
* on stores. `this.props` will not be available inside of `calculateState()`.
*
* This mixin will only `setState` not replace it, so you should always return
* every key in your state unless you know what you are doing.
*
* On the second calculateState when prevState is not null, the state will be
* updated to contain the previous foo AND the bar that was just returned. Only
* returning bar will not delete foo.
*/
declare function FluxMixinLegacy(stores: Array<FluxStore<any>>, options?: FluxMixinLegacy.Options): any;
export = FluxMixinLegacy;

36
types/flux/lib/FluxReduceStore.d.ts vendored Normal file
View File

@@ -0,0 +1,36 @@
import * as Store from "./FluxStore";
declare namespace FluxReduceStore { }
/**
* This is the basic building block of a Flux application. All of your stores
* should extend this class.
*/
declare abstract class FluxReduceStore<TState, TPayload> extends Store<TPayload> {
/**
* Getter that exposes the entire state of this store.
* If your state is not immutable you should override this and not expose state directly.
*/
getState(): TState;
/**
* Constructs the initial state for this store.
* This is called once during construction of the store.
*/
abstract getInitialState(): TState;
/**
* Reduces the current state, and an action to the new state of this store.
* All subclasses must implement this method.
* This method should be pure and have no side-effects.
*/
abstract reduce(state: TState, action: TPayload): TState;
/**
* Checks if two versions of state are the same.
* You do not need to override this if your state is immutable.
*/
areEqual(one: TState, two: TState): boolean;
}
export = FluxReduceStore;

74
types/flux/lib/FluxStore.d.ts vendored Normal file
View File

@@ -0,0 +1,74 @@
import * as Dispatcher from "./Dispatcher";
import * as fbEmitter from "fbemitter";
declare namespace FluxStore { }
/**
* This class represents the most basic functionality for a FluxStore. Do not
* extend this store directly; instead extend FluxReduceStore when creating a
* new store.
*/
declare abstract class FluxStore<TPayload> {
/**
* Constructs and registers an instance of this store with the given dispatcher.
*/
constructor(dispatcher: Dispatcher<TPayload>);
/**
* Adds a listener to the store, when the store changes the given callback will be called.
* A token is returned that can be used to remove the listener.
* Calling the remove() function on the returned token will remove the listener.
*/
addListener(callback: () => void): fbEmitter.EventSubscription;
/**
* Returns the dispatcher this store is registered with.
*/
getDispatcher(): Dispatcher<TPayload>;
/**
* Returns the dispatch token that the dispatcher recognizes this store by.
* Can be used to waitFor() this store.
*/
getDispatchToken(): string;
/**
* Ask if a store has changed during the current dispatch.
* Can only be invoked while dispatching.
* This can be used for constructing derived stores that depend on data from other stores.
*/
hasChanged(): boolean;
/**
* Emit an event notifying all listeners that this store has changed.
* This can only be invoked when dispatching.
* Changes are de-duplicated and resolved at the end of this store's __onDispatch function.
*/
protected __emitChange(): void;
/**
* This method encapsulates all logic for invoking __onDispatch. It should
* be used for things like catching changes and emitting them after the
* subclass has handled a payload.
*/
protected __invokeOnDispatch(payload: TPayload): void;
/**
* Subclasses must override this method.
* This is how the store receives actions from the dispatcher.
* All state mutation logic must be done during this method.
*/
protected __onDispatch(payload: TPayload): void;
protected __changed: boolean;
protected __changeEvent: string;
protected __className: string;
protected __dispatcher: Dispatcher<TPayload>;
protected __emitter: fbEmitter.EventEmitter;
}
export = FluxStore;

71
types/flux/test/Flux.ts Normal file
View File

@@ -0,0 +1,71 @@
import { Dispatcher } from "flux";
enum ActionSource {
Server,
View
}
enum ActionType {
Create,
Update,
Delete
}
interface Action {
source: ActionSource;
type: ActionType;
data: {};
}
function dispatcherCallback(payload: Action) {
let source: ActionSource = payload.source;
let type: ActionType = payload.type;
let data: {} = payload.data;
}
let dispatcherIsDispatching: boolean;
let dispatcherToken: string;
const actionPayload = {
data: {},
source: ActionSource.Server,
type: ActionType.Create
};
/**
* Basic dispatcher
*/
const basicDispatcher: Dispatcher<Action> = new Dispatcher<Action>();
dispatcherToken = basicDispatcher.register(dispatcherCallback);
basicDispatcher.unregister(dispatcherToken);
basicDispatcher.waitFor([dispatcherToken]);
basicDispatcher.dispatch(actionPayload);
dispatcherIsDispatching = basicDispatcher.isDispatching();
/**
* Custom dispatcher
*/
class CustomDispatcher extends Dispatcher<Action> {
// Dispatch an action with server as source
handleServerAction(type: ActionType, data: {}) {
this.dispatch({
source: ActionSource.Server,
type,
data
});
}
// Dispatch an action with view as source
handleViewAction(type: ActionType, data: {}) {
this.dispatch({
source: ActionSource.View,
type,
data
});
}
}
const customDispatcher: CustomDispatcher = new CustomDispatcher();
dispatcherToken = customDispatcher.register(dispatcherCallback);
customDispatcher.unregister(dispatcherToken);
customDispatcher.dispatch(actionPayload);
customDispatcher.waitFor([dispatcherToken]);
dispatcherIsDispatching = customDispatcher.isDispatching();

View File

@@ -0,0 +1,80 @@
import { Dispatcher } from "flux";
import { ReduceStore, Container } from "flux/utils";
import * as React from "react";
interface Payload {
type: string;
}
const basicDispatcher = new Dispatcher<Payload>();
// Sample Reduce Store
class CounterStore extends ReduceStore<number, any> {
getInitialState(): number {
return 0;
}
reduce(state: number, action: Payload): number {
switch (action.type) {
case 'increment':
return state + 1;
case 'square':
return state * state;
default:
return state;
}
}
}
const Store = new CounterStore(basicDispatcher);
// Sample Flux container with Store
interface Props {
a: string;
b: boolean;
}
interface State {
counter: number;
}
class CounterContainer extends React.Component<Props, State> {
static getStores() {
return [Store];
}
static a: string = "asd";
static calculateState(prevState: State, props: Props): State {
return {
counter: Store.getState() - (props.b ? 0 : 1)
};
}
render() {
return <div>
{this.state.counter}
</div>;
}
}
const ContainerComponent1 = Container.create(CounterContainer, { withProps: true });
<ContainerComponent1 a="string" b={false} />;
const ContainerComponent2 = Container.create<Props>(CounterContainer, { withProps: true });
<ContainerComponent2 a="string" b={false} />;
const ContainerComponent3 = Container.create<Props, State>(CounterContainer, { withProps: true });
<ContainerComponent3 a="string" b={false} />;
// Functional flux container with Store
const FunctionalContainerComponent = Container.createFunctional<Props, State>(
(props) => {
return <div>
{props.a} {props.b}
</div>;
},
() => [Store],
(prevState) => ({ counter: Store.getState() })
);
<FunctionalContainerComponent a="string" b={true} />;

View File

@@ -5,20 +5,27 @@
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": false,
"baseUrl": "../",
"typeRoots": [
"../"
],
"jsx": "react",
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true
},
"files": [
"index.d.ts",
"utils/index.d.ts",
"flux-tests.ts"
"utils.d.ts",
"lib/Dispatcher.d.ts",
"lib/FluxContainer.d.ts",
"lib/FluxMixinLegacy.d.ts",
"lib/FluxReduceStore.d.ts",
"lib/FluxStore.d.ts",
"test/Flux.ts",
"test/FluxUtils.tsx"
]
}

3
types/flux/tslint.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}

11
types/flux/utils.d.ts vendored Normal file
View File

@@ -0,0 +1,11 @@
import * as Container from "./lib/FluxContainer";
import * as Mixin from "./lib/FluxMixinLegacy";
import * as ReduceStore from "./lib/FluxReduceStore";
import * as Store from "./lib/FluxStore";
export {
Container,
Mixin,
ReduceStore,
Store
};

View File

@@ -1,140 +0,0 @@
// Type definitions for Flux Utils 3.0
// Project: http://facebook.github.io/flux/
// Definitions by: Steve Baker <https://github.com/stkb/>, Giedrius Grabauskas <https://github.com/GiedriusGrabauskas/>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
/// <reference types="react" />
/// <reference types="flux" />
/// <reference types="fbemitter" />
import * as React from 'react';
import * as Flux from 'flux';
import * as fbEmitter from 'fbemitter';
export = FluxUtils;
declare namespace FluxUtils {
/**
* Default options to create a Container with
*
* @interface RealOptions
*/
interface RealOptions {
/**
* Default value: true
*
* @type {boolean}
*/
pure?: boolean;
/**
* Default value: false
*
* @type {boolean}
*/
withProps?: boolean;
/**
* Default value: false
*
* @type {boolean}
*/
withContext?: boolean;
}
export class Container {
constructor();
/**
* Create is used to transform a react class into a container
* that updates its state when relevant stores change.
* The provided base class must have static methods getStores() and calculateState().
*/
static create<TComponent>(base: React.ComponentClass<TComponent>, options?: RealOptions): React.ComponentClass<TComponent>;
/**
* This is a way to connect stores to a functional stateless view
*/
static createFunctional<Props, State>(
viewFn: (props: State) => React.ReactElement<State>,
getStores: (props?: Props, context?: any) => FluxUtils.Store<any>[],
calculateState: (prevState?: State, props?: Props, context?: any) => State,
options?: RealOptions
): React.ComponentClass<Props>;
}
export class ReduceStore<T, TPayload> extends Store<TPayload> {
/**
* Getter that exposes the entire state of this store.
* If your state is not immutable you should override this and not expose state directly.
*/
getState(): T;
/**
* Constructs the initial state for this store.
* This is called once during construction of the store.
*/
getInitialState(): T;
/**
* Reduces the current state, and an action to the new state of this store.
* All subclasses must implement this method.
* This method should be pure and have no side-effects.
*/
reduce(state: T, action: TPayload): T;
/**
* Checks if two versions of state are the same.
* You do not need to override this if your state is immutable.
*/
areEqual(one: T, two: T): boolean;
}
export class Store<TPayload> {
/**
* Constructs and registers an instance of this store with the given dispatcher.
*/
constructor(dispatcher: Flux.Dispatcher<TPayload>);
/**
* Adds a listener to the store, when the store changes the given callback will be called.
* A token is returned that can be used to remove the listener.
* Calling the remove() function on the returned token will remove the listener.
*/
addListener(callback: Function): fbEmitter.EventSubscription;
/**
* Returns the dispatcher this store is registered with.
*/
getDispatcher(): Flux.Dispatcher<TPayload>;
/**
* Returns the dispatch token that the dispatcher recognizes this store by.
* Can be used to waitFor() this store.
*/
getDispatchToken(): string;
/**
* Ask if a store has changed during the current dispatch.
* Can only be invoked while dispatching.
* This can be used for constructing derived stores that depend on data from other stores.
*/
hasChanged(): boolean;
/**
*Emit an event notifying all listeners that this store has changed.
* This can only be invoked when dispatching.
* Changes are de-duplicated and resolved at the end of this store's __onDispatch function.
*/
__emitChange(): void;
/**
* Subclasses must override this method.
* This is how the store receives actions from the dispatcher.
* All state mutation logic must be done during this method.
*/
__onDispatch(payload: TPayload): void;
}
}