Fix linting error in packages/redux

This commit is contained in:
Jerko Steiner 2019-09-15 16:20:52 +07:00
parent 8c732ba91e
commit 003032c3ef
27 changed files with 216 additions and 106 deletions

View File

@ -1,7 +1,11 @@
extends: extends:
- eslint:recommended - eslint:recommended
- plugin:react/recommended
- plugin:@typescript-eslint/eslint-recommended - plugin:@typescript-eslint/eslint-recommended
- plugin:@typescript-eslint/recommended - plugin:@typescript-eslint/recommended
settings:
react:
version: 'detect'
rules: rules:
max-len: max-len:
- warn - warn

116
package-lock.json generated
View File

@ -3059,6 +3059,16 @@
"integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=",
"dev": true "dev": true
}, },
"array-includes": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
"integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.7.0"
}
},
"array-map": { "array-map": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
@ -6455,6 +6465,54 @@
} }
} }
}, },
"eslint-plugin-react": {
"version": "7.14.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz",
"integrity": "sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==",
"dev": true,
"requires": {
"array-includes": "^3.0.3",
"doctrine": "^2.1.0",
"has": "^1.0.3",
"jsx-ast-utils": "^2.1.0",
"object.entries": "^1.1.0",
"object.fromentries": "^2.0.0",
"object.values": "^1.1.0",
"prop-types": "^15.7.2",
"resolve": "^1.10.1"
},
"dependencies": {
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"requires": {
"esutils": "^2.0.2"
}
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"dev": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
},
"resolve": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
"integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
}
}
}
},
"eslint-scope": { "eslint-scope": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
@ -10112,6 +10170,16 @@
"verror": "1.10.0" "verror": "1.10.0"
} }
}, },
"jsx-ast-utils": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz",
"integrity": "sha512-v3FxCcAf20DayI+uxnCuw795+oOIkVu6EnJ1+kSzhqqTZHNkTZ7B66ZgLp4oLJ/gbA64cI0B7WRoHZMSRdyVRQ==",
"dev": true,
"requires": {
"array-includes": "^3.0.3",
"object.assign": "^4.1.0"
}
},
"kind-of": { "kind-of": {
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
@ -11700,6 +11768,42 @@
"isobject": "^3.0.0" "isobject": "^3.0.0"
} }
}, },
"object.assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"has-symbols": "^1.0.0",
"object-keys": "^1.0.11"
}
},
"object.entries": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz",
"integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.12.0",
"function-bind": "^1.1.1",
"has": "^1.0.3"
}
},
"object.fromentries": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz",
"integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.11.0",
"function-bind": "^1.1.1",
"has": "^1.0.1"
}
},
"object.getownpropertydescriptors": { "object.getownpropertydescriptors": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
@ -11719,6 +11823,18 @@
"isobject": "^3.0.1" "isobject": "^3.0.1"
} }
}, },
"object.values": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz",
"integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.12.0",
"function-bind": "^1.1.1",
"has": "^1.0.3"
}
},
"octokit-pagination-methods": { "octokit-pagination-methods": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz",

View File

@ -59,6 +59,7 @@
"common-shakeify": "^0.6.0", "common-shakeify": "^0.6.0",
"cookie-parser": "^1.4.4", "cookie-parser": "^1.4.4",
"deep-object-diff": "^1.1.0", "deep-object-diff": "^1.1.0",
"eslint-plugin-react": "^7.14.3",
"esmify": "git+https://github.com/jeremija/esmify.git", "esmify": "git+https://github.com/jeremija/esmify.git",
"formik": "^1.5.8", "formik": "^1.5.8",
"history": "^4.9.0", "history": "^4.9.0",

View File

@ -0,0 +1,4 @@
export interface Action<T, ActionType extends string> {
payload: T
type: ActionType
}

View File

@ -0,0 +1,10 @@
import {PendingAction} from './PendingAction'
import {ResolvedAction} from './ResolvedAction'
import {RejectedAction} from './RejectedAction'
export type TAsyncStatus = 'pending' | 'resolved' | 'rejected'
export type AsyncAction<T, ActionType extends string> =
PendingAction<T, ActionType>
| ResolvedAction<T, ActionType>
| RejectedAction<ActionType>

View File

@ -1,6 +1,6 @@
import {IAction} from './IAction' import {Action} from './Action'
export type TGetAction<ActionTypes, T extends string> = export type TGetAction<ActionTypes, T extends string> =
ActionTypes extends IAction<infer U, T> ActionTypes extends Action<infer U, T>
? ActionTypes ? ActionTypes
: never : never

View File

@ -0,0 +1,6 @@
import {AsyncAction} from './AsyncAction'
export type GetPendingAction<MyTypes, T extends string> =
MyTypes extends AsyncAction<infer U, T> & {status: 'pending'}
? MyTypes
: never

View File

@ -0,0 +1,6 @@
import {AsyncAction} from './AsyncAction'
export type GetResolvedAction<MyTypes, T extends string> =
MyTypes extends AsyncAction<infer U, T> & {status: 'resolved'}
? MyTypes
: never

View File

@ -1,4 +0,0 @@
export interface IAction<T, ActionType extends string> {
payload: T
type: ActionType
}

View File

@ -1,6 +0,0 @@
import {IAction} from './IAction'
export interface IPendingAction<T, ActionType extends string> extends
IAction<Promise<T>, ActionType> {
status: 'pending'
}

View File

@ -1,6 +0,0 @@
import {IAction} from './IAction'
export interface IRejectedAction<ActionType extends string> extends
IAction<Error, ActionType> {
status: 'rejected'
}

View File

@ -1,7 +0,0 @@
import {IAction} from './IAction'
export interface IResolvedAction<T, ActionType extends string> extends
IAction<T, ActionType> {
payload: T
status: 'resolved'
}

View File

@ -1,9 +1,6 @@
import {IPendingAction} from './IPendingAction' import {Action} from './Action'
export class PendingAction<T, ActionType extends string> { export interface PendingAction<T, ActionType extends string> extends
readonly status = 'pending' Action<Promise<T>, ActionType> {
constructor( status: 'pending'
readonly payload: T,
readonly type: ActionType,
) {}
} }

View File

@ -0,0 +1,6 @@
import {Action} from './Action'
export interface RejectedAction<ActionType extends string> extends
Action<Error, ActionType> {
status: 'rejected'
}

View File

@ -0,0 +1,7 @@
import {Action} from './Action'
export interface ResolvedAction<T, ActionType extends string> extends
Action<T, ActionType> {
payload: T
status: 'resolved'
}

View File

@ -1,10 +0,0 @@
import {IPendingAction} from './IPendingAction'
import {IResolvedAction} from './IResolvedAction'
import {IRejectedAction} from './IRejectedAction'
export type TAsyncStatus = 'pending' | 'resolved' | 'rejected'
export type TAsyncAction<T, ActionType extends string> =
IPendingAction<T, ActionType>
| IResolvedAction<T, ActionType>
| IRejectedAction<ActionType>

View File

@ -1,6 +0,0 @@
import {TAsyncAction} from './TAsyncAction'
export type TGetPendingAction<MyTypes, T extends string> =
MyTypes extends TAsyncAction<infer U, T> & {status: 'pending'}
? MyTypes
: never

View File

@ -1,6 +0,0 @@
import {TAsyncAction} from './TAsyncAction'
export type TGetResolvedAction<MyTypes, T extends string> =
MyTypes extends TAsyncAction<infer U, T> & {status: 'resolved'}
? MyTypes
: never

View File

@ -0,0 +1,8 @@
import {PendingAction} from './IPendingAction'
export function createPendingAction<T, ActionType extends string>(
payload: Promise<T>,
type: ActionType,
): PendingAction<T, ActionType> {
return {payload, type, status: 'pending'}
}

View File

@ -1,9 +1,9 @@
export * from './IAction' export * from './Action'
export * from './IPendingAction' export * from './createPendingAction'
export * from './IRejectedAction' export * from './RejectedAction'
export * from './IResolvedAction' export * from './ResolvedAction'
export * from './PendingAction' export * from './PendingAction'
export * from './TAsyncAction' export * from './AsyncAction'
export * from './TGetAction' export * from './GetAction'
export * from './TGetPendingAction' export * from './GetPendingAction'
export * from './TGetResolvedAction' export * from './GetResolvedAction'

View File

@ -4,5 +4,5 @@ export function bindActionCreators<T extends object>(
obj: T, obj: T,
dispatch: Dispatch, dispatch: Dispatch,
): T { ): T {
return bind(obj as any, dispatch) return bind(obj as any, dispatch) // eslint-disable-line
} }

View File

@ -1,9 +1,8 @@
import assert from 'assert'
import {AnyAction, Middleware} from 'redux' import {AnyAction, Middleware} from 'redux'
function isPromise(value: any): value is Promise<any> { function isPromise(value: unknown): value is Promise<unknown> {
return value && typeof value === 'object' && return value && typeof value === 'object' &&
typeof (value as any).then === 'function' typeof (value as Promise<unknown>).then === 'function'
} }
/** /**
@ -21,7 +20,7 @@ function isPromise(value: any): value is Promise<any> {
*/ */
export class PromiseMiddleware { export class PromiseMiddleware {
handle: Middleware = store => next => (action: AnyAction) => { handle: Middleware = store => next => (action: AnyAction) => {
const {payload, type} = action const {payload} = action
if (!isPromise(payload)) { if (!isPromise(payload)) {
return next(action) return next(action)
} }

View File

@ -1,14 +1,12 @@
import {WaitMiddleware} from './WaitMiddleware'
import {
IAction, IPendingAction, IResolvedAction, IRejectedAction,
} from '../actions'
import {applyMiddleware, createStore, AnyAction} from 'redux'
import { getError } from '@rondo.dev/test-utils' import { getError } from '@rondo.dev/test-utils'
import { applyMiddleware, createStore } from 'redux'
import { Action } from '../actions'
import { WaitMiddleware } from './WaitMiddleware'
describe('WaitMiddleware', () => { describe('WaitMiddleware', () => {
const getStore = (wm: WaitMiddleware) => createStore( const getStore = (wm: WaitMiddleware) => createStore(
(state: string[] = [], action: IAction<any, string>) => { (state: string[] = [], action: Action<any, string>) => {
return [...state, action.type] return [...state, action.type]
}, },
[], [],

View File

@ -1,15 +1,15 @@
import {TAsyncAction} from '../actions/TAsyncAction' import {AsyncAction} from '../actions/AsyncAction'
import {AnyAction, Middleware} from 'redux' import {AnyAction, Middleware} from 'redux'
export class WaitMiddleware { export class WaitMiddleware {
protected notify?: (action: TAsyncAction<any, string>) => void protected notify?: (action: AsyncAction<unknown, string>) => void
protected recorders: Recorder[] = [] protected recorders: Recorder[] = []
handle: Middleware = store => next => (action: AnyAction) => { handle: Middleware = () => next => (action: AnyAction) => {
next(action) next(action)
this.recorders.forEach(recorder => recorder.record(action)) this.recorders.forEach(recorder => recorder.record(action))
if (this.notify && 'status' in action) { if (this.notify && 'status' in action) {
this.notify(action as TAsyncAction<any, string>) this.notify(action as AsyncAction<unknown, string>)
} }
} }
@ -66,7 +66,7 @@ export class WaitMiddleware {
this.notify = undefined this.notify = undefined
}, timeout) }, timeout)
this.notify = (action: TAsyncAction<any, string>) => { this.notify = (action: AsyncAction<unknown, string>) => {
if (!actionsByName[action.type]) { if (!actionsByName[action.type]) {
return return
} }
@ -77,11 +77,13 @@ export class WaitMiddleware {
actionsByName[action.type]-- actionsByName[action.type]--
count-- count--
if (count === 0) { if (count === 0) {
clearTimeout(t)
resolve() resolve()
this.notify = undefined this.notify = undefined
} }
return return
case 'rejected': case 'rejected':
clearTimeout(t)
reject(action.payload) reject(action.payload)
this.notify = undefined this.notify = undefined
return return

View File

@ -7,19 +7,19 @@ import { pack, TStateSelector } from './pack'
describe('pack', () => { describe('pack', () => {
interface IChangeAction { interface ChangeAction {
payload: {a: number, b: string}, payload: {a: number, b: string}
type: 'CHANGE' type: 'CHANGE'
} }
interface IProps { interface Props {
a: number a: number
b: string b: string
update(a: number, b: string): IChangeAction update(a: number, b: string): ChangeAction
c: string[] c: string[]
} }
class PureComponent extends React.PureComponent<IProps> { class PureComponent extends React.PureComponent<Props> {
update = () => { update = () => {
this.props.update(1, 'one') this.props.update(1, 'one')
} }
@ -34,7 +34,7 @@ describe('pack', () => {
} }
} }
function FunctionalComponent(props: IProps) { function FunctionalComponent(props: Props) {
const update = useCallback(() => props.update(1, 'one'), []) const update = useCallback(() => props.update(1, 'one'), [])
return ( return (
@ -44,15 +44,15 @@ describe('pack', () => {
) )
} }
type LocalState = Omit<IProps, 'c' | 'update'> type LocalState = Omit<Props, 'c' | 'update'>
interface IState { interface State {
localState: LocalState localState: LocalState
} }
function reduce( function reduce(
state: IState = {localState: {a: 0, b: ''}}, state: State = {localState: {a: 0, b: ''}},
action: any, action: any,
): IState { ): State {
switch (action.type) { switch (action.type) {
case 'CHANGE': case 'CHANGE':
return { return {
@ -73,7 +73,7 @@ describe('pack', () => {
getLocalState, getLocalState,
(localState: LocalState) => localState, (localState: LocalState) => localState,
{ {
update(a: number, b: string): IChangeAction { update(a: number, b: string): ChangeAction {
return { return {
payload: {a, b}, payload: {a, b},
type: 'CHANGE', type: 'CHANGE',
@ -91,7 +91,7 @@ describe('pack', () => {
getLocalState, getLocalState,
(localState: LocalState) => localState, (localState: LocalState) => localState,
{ {
update(a: number, b: string): IChangeAction { update(a: number, b: string): ChangeAction {
return { return {
payload: {a, b}, payload: {a, b},
type: 'CHANGE', type: 'CHANGE',
@ -102,10 +102,10 @@ describe('pack', () => {
) )
} }
const PackedPureComponent = configurePureComponent<IState>( const PackedPureComponent = configurePureComponent<State>(
state => state.localState) state => state.localState)
const PackedFunctionalComponent = configureFunctionalComponent<IState>( const PackedFunctionalComponent = configureFunctionalComponent<State>(
state => state.localState) state => state.localState)
it('creates a connected component', () => { it('creates a connected component', () => {

View File

@ -1,6 +1,4 @@
import { ComponentType, PureComponent } from 'react' import { connect, GetProps, MapDispatchToPropsParam, Matching, ResolveThunks } from 'react-redux'
import { connect, Omit, MapDispatchToPropsParam, Matching, GetProps, ResolveThunks } from 'react-redux'
import { Dispatch } from 'redux'
/* /*
* Select and return a part of the state * Select and return a part of the state

View File

@ -1,14 +1,7 @@
import {ReduxLogger, PromiseMiddleware, WaitMiddleware} from '../middleware' import { Action, applyMiddleware, createStore as create, DeepPartial, Middleware, Reducer } from 'redux'
import { import { PromiseMiddleware, ReduxLogger } from '../middleware'
applyMiddleware,
createStore as create,
Middleware,
Action,
DeepPartial,
Reducer,
} from 'redux'
export interface ICreateStoreParams<State, A extends Action> { export interface CreateStoreParams<State, A extends Action> {
reducer: Reducer<State, A> reducer: Reducer<State, A>
state?: Partial<State> state?: Partial<State>
middleware?: Middleware[] middleware?: Middleware[]
@ -19,7 +12,7 @@ export interface ICreateStoreParams<State, A extends Action> {
* Create a Redux store. * Create a Redux store.
*/ */
export function createStore<State, A extends Action>( export function createStore<State, A extends Action>(
params: ICreateStoreParams<State, A>, params: CreateStoreParams<State, A>,
) { ) {
const middleware = params.middleware || [ const middleware = params.middleware || [
new ReduxLogger( new ReduxLogger(