From 211cdff78045edaa3a7721d1b9d408be232d425e Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 11:18:21 +0100 Subject: [PATCH 01/12] Context.ts --- src/components/{Context.js => Context.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/components/{Context.js => Context.ts} (100%) diff --git a/src/components/Context.js b/src/components/Context.ts similarity index 100% rename from src/components/Context.js rename to src/components/Context.ts From 5e6c80d36c7209c4ca351e3013410055019436dd Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 11:20:01 +0100 Subject: [PATCH 02/12] allow JSX in tsconfig --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 97a0dae15..8bddcdad3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,7 @@ // "lib": [], /* Specify library files to be included in the compilation. */ "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ "declaration": true, /* Generates corresponding '.d.ts' file. */ "emitDeclarationOnly": true, // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ From 286a131d26a556d894eb4931a32f3e665e94d9a1 Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 11:28:13 +0100 Subject: [PATCH 03/12] Provider.tsx --- src/components/Context.ts | 7 ++++++- src/components/{Provider.js => Provider.tsx} | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) rename src/components/{Provider.js => Provider.tsx} (83%) diff --git a/src/components/Context.ts b/src/components/Context.ts index a706d517f..6617a3ab3 100644 --- a/src/components/Context.ts +++ b/src/components/Context.ts @@ -1,6 +1,11 @@ import React from 'react' +import type Subscription from '../utils/Subscription' -export const ReactReduxContext = /*#__PURE__*/ React.createContext(null) +export type ReduxContextProps = { + store: any, + subscription: Subscription, +} +export const ReactReduxContext = /*#__PURE__*/ React.createContext(null) if (process.env.NODE_ENV !== 'production') { ReactReduxContext.displayName = 'ReactRedux' diff --git a/src/components/Provider.js b/src/components/Provider.tsx similarity index 83% rename from src/components/Provider.js rename to src/components/Provider.tsx index fdfc48b75..d501238a2 100644 --- a/src/components/Provider.js +++ b/src/components/Provider.tsx @@ -1,10 +1,10 @@ -import React, { useMemo } from 'react' +import React, { ReactNode, useMemo } from 'react' import PropTypes from 'prop-types' -import { ReactReduxContext } from './Context' +import { ReactReduxContext, ReduxContextProps } from './Context' import Subscription from '../utils/Subscription' import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect' -function Provider({ store, context, children }) { +function Provider({ store, context, children }: { store: any, context?: React.Context, children: ReactNode }) { const contextValue = useMemo(() => { const subscription = new Subscription(store) subscription.onStateChange = subscription.notifyNestedSubs From 5d71c4498b1e0c28cee461c263438450d99e4eba Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 11:47:23 +0100 Subject: [PATCH 04/12] Subscription.tsx --- src/components/Provider.tsx | 2 +- .../{Subscription.js => Subscription.ts} | 42 ++++++++++++------- 2 files changed, 27 insertions(+), 17 deletions(-) rename src/utils/{Subscription.js => Subscription.ts} (71%) diff --git a/src/components/Provider.tsx b/src/components/Provider.tsx index d501238a2..97e12c52e 100644 --- a/src/components/Provider.tsx +++ b/src/components/Provider.tsx @@ -25,7 +25,7 @@ function Provider({ store, context, children }: { store: any, context?: React.Co } return () => { subscription.tryUnsubscribe() - subscription.onStateChange = null + subscription.onStateChange = undefined } }, [contextValue, previousState]) diff --git a/src/utils/Subscription.js b/src/utils/Subscription.ts similarity index 71% rename from src/utils/Subscription.js rename to src/utils/Subscription.ts index 7030ec84a..aeaa6c5fc 100644 --- a/src/utils/Subscription.js +++ b/src/utils/Subscription.ts @@ -4,12 +4,16 @@ import { getBatch } from './batch' // well as nesting subscriptions of descendant components, so that we can ensure the // ancestor components re-render before descendants -const nullListeners = { notify() {} } +type Listener = { + callback: () => void; + next: Listener | null; + prev: Listener | null; +}; function createListenerCollection() { const batch = getBatch() - let first = null - let last = null + let first: Listener | null = null + let last: Listener | null = null return { clear() { @@ -37,7 +41,7 @@ function createListenerCollection() { return listeners }, - subscribe(callback) { + subscribe(callback: () => void) { let isSubscribed = true let listener = (last = { @@ -57,6 +61,7 @@ function createListenerCollection() { isSubscribed = false if (listener.next) { + //@ts-expect-error -- listener.next is always null listener.next.prev = listener.prev } else { last = listener.prev @@ -71,29 +76,35 @@ function createListenerCollection() { } } +type ListenerCollection = ReturnType; + export default class Subscription { - constructor(store, parentSub) { + private store: any; + private parentSub?: Subscription; + private unsubscribe?: () => void; + private listeners?: ListenerCollection; + public onStateChange?: () => void; + + constructor(store: any, parentSub?: Subscription) { this.store = store this.parentSub = parentSub - this.unsubscribe = null - this.listeners = nullListeners + this.unsubscribe = undefined + this.listeners = undefined this.handleChangeWrapper = this.handleChangeWrapper.bind(this) } - addNestedSub(listener) { + addNestedSub(listener: () => void) { this.trySubscribe() - return this.listeners.subscribe(listener) + return this.listeners?.subscribe(listener) } notifyNestedSubs() { - this.listeners.notify() + this.listeners?.notify() } handleChangeWrapper() { - if (this.onStateChange) { - this.onStateChange() - } + this.onStateChange?.() } isSubscribed() { @@ -113,9 +124,8 @@ export default class Subscription { tryUnsubscribe() { if (this.unsubscribe) { this.unsubscribe() - this.unsubscribe = null - this.listeners.clear() - this.listeners = nullListeners + this.unsubscribe = undefined + this.listeners?.clear() } } } From 1e49d3c4bfd333a7a425373d16918e8d2cfb345c Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 11:53:32 +0100 Subject: [PATCH 05/12] zero-out listeners --- src/utils/Subscription.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/Subscription.ts b/src/utils/Subscription.ts index aeaa6c5fc..86b9956d9 100644 --- a/src/utils/Subscription.ts +++ b/src/utils/Subscription.ts @@ -126,6 +126,7 @@ export default class Subscription { this.unsubscribe() this.unsubscribe = undefined this.listeners?.clear() + this.listeners = undefined; } } } From 7865ed27a9737bfeba62437f8300f0517eaee279 Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 12:06:25 +0100 Subject: [PATCH 06/12] rollup supports .tsx? --- rollup.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollup.config.js b/rollup.config.js index 4013edac5..d4d6330c3 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,7 +7,7 @@ import pkg from './package.json' const env = process.env.NODE_ENV -const extensions = ['.js', '.ts', '.json'] +const extensions = ['.js', '.ts', '.tsx', '.json'] const config = { input: 'src/index.js', From 2966e302091a1e6e95cb5fd4eb4903b829313120 Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 12:18:42 +0100 Subject: [PATCH 07/12] Fixed compilation error --- src/utils/Subscription.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/Subscription.ts b/src/utils/Subscription.ts index 86b9956d9..8edb637a0 100644 --- a/src/utils/Subscription.ts +++ b/src/utils/Subscription.ts @@ -44,7 +44,7 @@ function createListenerCollection() { subscribe(callback: () => void) { let isSubscribed = true - let listener = (last = { + let listener: Listener = (last = { callback, next: null, prev: last, @@ -61,7 +61,6 @@ function createListenerCollection() { isSubscribed = false if (listener.next) { - //@ts-expect-error -- listener.next is always null listener.next.prev = listener.prev } else { last = listener.prev From 088504b788025c9106e2b7655508995e91890430 Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 12:26:49 +0100 Subject: [PATCH 08/12] removed semi-colons to stay in line with existing styles --- src/components/Context.ts | 4 ++-- src/utils/Subscription.ts | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/components/Context.ts b/src/components/Context.ts index 6617a3ab3..9de101d4f 100644 --- a/src/components/Context.ts +++ b/src/components/Context.ts @@ -2,8 +2,8 @@ import React from 'react' import type Subscription from '../utils/Subscription' export type ReduxContextProps = { - store: any, - subscription: Subscription, + store: any + subscription: Subscription } export const ReactReduxContext = /*#__PURE__*/ React.createContext(null) diff --git a/src/utils/Subscription.ts b/src/utils/Subscription.ts index 8edb637a0..d708e3b32 100644 --- a/src/utils/Subscription.ts +++ b/src/utils/Subscription.ts @@ -5,10 +5,10 @@ import { getBatch } from './batch' // ancestor components re-render before descendants type Listener = { - callback: () => void; - next: Listener | null; - prev: Listener | null; -}; + callback: () => void + next: Listener | null + prev: Listener | null +} function createListenerCollection() { const batch = getBatch() @@ -75,14 +75,14 @@ function createListenerCollection() { } } -type ListenerCollection = ReturnType; +type ListenerCollection = ReturnType export default class Subscription { - private store: any; - private parentSub?: Subscription; - private unsubscribe?: () => void; - private listeners?: ListenerCollection; - public onStateChange?: () => void; + private store: any + private parentSub?: Subscription + private unsubscribe?: () => void + private listeners?: ListenerCollection + public onStateChange?: () => void constructor(store: any, parentSub?: Subscription) { this.store = store @@ -125,7 +125,7 @@ export default class Subscription { this.unsubscribe() this.unsubscribe = undefined this.listeners?.clear() - this.listeners = undefined; + this.listeners = undefined } } } From 420891dd22e4d129e5fa9789c34c9e3e59f531da Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 16:29:57 +0100 Subject: [PATCH 09/12] Use types that came from the typedef package --- src/components/Context.ts | 9 ++++++--- src/components/Provider.tsx | 22 +++++++++++++++++++--- src/types.ts | 1 + 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 src/types.ts diff --git a/src/components/Context.ts b/src/components/Context.ts index 9de101d4f..7ae9a4f9e 100644 --- a/src/components/Context.ts +++ b/src/components/Context.ts @@ -1,11 +1,14 @@ import React from 'react' +import { Action, AnyAction, Store } from 'redux' +import type { FixTypeLater } from '../types' import type Subscription from '../utils/Subscription' -export type ReduxContextProps = { - store: any +export interface ReactReduxContextValue { + store: Store; subscription: Subscription } -export const ReactReduxContext = /*#__PURE__*/ React.createContext(null) + +export const ReactReduxContext = /*#__PURE__*/ React.createContext(null) if (process.env.NODE_ENV !== 'production') { ReactReduxContext.displayName = 'ReactRedux' diff --git a/src/components/Provider.tsx b/src/components/Provider.tsx index 97e12c52e..6033f048a 100644 --- a/src/components/Provider.tsx +++ b/src/components/Provider.tsx @@ -1,10 +1,26 @@ -import React, { ReactNode, useMemo } from 'react' +import React, { Context, ReactNode, useMemo } from 'react' import PropTypes from 'prop-types' -import { ReactReduxContext, ReduxContextProps } from './Context' +import { ReactReduxContext, ReactReduxContextValue } from './Context' import Subscription from '../utils/Subscription' import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect' +import type { FixTypeLater } from '../types' +import { Action, AnyAction, Store } from 'redux' -function Provider({ store, context, children }: { store: any, context?: React.Context, children: ReactNode }) { +interface ProviderProps { + /** + * The single Redux store in your application. + */ + store: Store; + /** + * Optional context to be used internally in react-redux. Use React.createContext() to create a context to be used. + * If this is used, generate own connect HOC by using connectAdvanced, supplying the same context provided to the + * Provider. Initial value doesn't matter, as it is overwritten with the internal state of Provider. + */ + context?: Context; + children: ReactNode +} + +function Provider({ store, context, children }: ProviderProps) { const contextValue = useMemo(() => { const subscription = new Subscription(store) subscription.onStateChange = subscription.notifyNestedSubs diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 000000000..6d1ef8e8d --- /dev/null +++ b/src/types.ts @@ -0,0 +1 @@ +export type FixTypeLater = any; \ No newline at end of file From e4eacc9b3e6de1f9ecf64ef95ec50773f92796e7 Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 16:30:56 +0100 Subject: [PATCH 10/12] linting --- src/components/Context.ts | 2 +- src/components/Provider.tsx | 4 ++-- src/types.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Context.ts b/src/components/Context.ts index 7ae9a4f9e..a360c01b9 100644 --- a/src/components/Context.ts +++ b/src/components/Context.ts @@ -4,7 +4,7 @@ import type { FixTypeLater } from '../types' import type Subscription from '../utils/Subscription' export interface ReactReduxContextValue { - store: Store; + store: Store subscription: Subscription } diff --git a/src/components/Provider.tsx b/src/components/Provider.tsx index 6033f048a..6593b673f 100644 --- a/src/components/Provider.tsx +++ b/src/components/Provider.tsx @@ -10,13 +10,13 @@ interface ProviderProps { /** * The single Redux store in your application. */ - store: Store; + store: Store /** * Optional context to be used internally in react-redux. Use React.createContext() to create a context to be used. * If this is used, generate own connect HOC by using connectAdvanced, supplying the same context provided to the * Provider. Initial value doesn't matter, as it is overwritten with the internal state of Provider. */ - context?: Context; + context?: Context children: ReactNode } diff --git a/src/types.ts b/src/types.ts index 6d1ef8e8d..d8b25c80f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1 +1 @@ -export type FixTypeLater = any; \ No newline at end of file +export type FixTypeLater = any \ No newline at end of file From 6a617e2693f9742b52e08707385dd8ce8ebf9d49 Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 16:33:37 +0100 Subject: [PATCH 11/12] less changes --- src/components/Context.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Context.ts b/src/components/Context.ts index a360c01b9..684438771 100644 --- a/src/components/Context.ts +++ b/src/components/Context.ts @@ -3,8 +3,8 @@ import { Action, AnyAction, Store } from 'redux' import type { FixTypeLater } from '../types' import type Subscription from '../utils/Subscription' -export interface ReactReduxContextValue { - store: Store +export interface ReactReduxContextValue { + store: Store subscription: Subscription } From f1a4dbc07c6f1fd1ff2b019ee33197d00b7079c3 Mon Sep 17 00:00:00 2001 From: Jeroen Vannevel Date: Sat, 26 Jun 2021 16:53:21 +0100 Subject: [PATCH 12/12] Removed PropTypes --- src/components/Provider.tsx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/components/Provider.tsx b/src/components/Provider.tsx index 6593b673f..bbd84d0a1 100644 --- a/src/components/Provider.tsx +++ b/src/components/Provider.tsx @@ -1,5 +1,4 @@ import React, { Context, ReactNode, useMemo } from 'react' -import PropTypes from 'prop-types' import { ReactReduxContext, ReactReduxContextValue } from './Context' import Subscription from '../utils/Subscription' import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect' @@ -50,16 +49,4 @@ function Provider({ store, context, children }: ProviderProps) { return {children} } -if (process.env.NODE_ENV !== 'production') { - Provider.propTypes = { - store: PropTypes.shape({ - subscribe: PropTypes.func.isRequired, - dispatch: PropTypes.func.isRequired, - getState: PropTypes.func.isRequired, - }), - context: PropTypes.object, - children: PropTypes.any, - } -} - export default Provider