From bae869f2cef39616a7cf09da5c5334492dbbc44f Mon Sep 17 00:00:00 2001 From: Lenilson Nascimento Date: Thu, 17 Feb 2022 12:41:48 +0100 Subject: [PATCH] fix(types): fixed types for PartialState --- .eslintrc.yml | 2 + .gitignore | 3 +- examples/05_typescript/package.json | 1 - examples/05_typescript/tsconfig.json | 6 +- package.json | 2 + src/Observable.ts | 8 +- src/createGlobalState.ts | 16 ++-- src/createHook.ts | 15 +++- src/createReadOnlyHook.ts | 7 +- src/rehydrate.ts | 6 +- src/types.ts | 23 ++--- tsconfig.json | 2 +- yarn.lock | 122 +++++++++++++++++++++++++-- 13 files changed, 173 insertions(+), 40 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 65b10c12..3c3de38d 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -15,6 +15,8 @@ extends: - plugin:import/errors - plugin:import/warnings - plugin:import/typescript + - plugin:react/recommended + - plugin:react-hooks/recommended - prettier settings: import/resolver: diff --git a/.gitignore b/.gitignore index f22ee27f..8a03c220 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ lib .DS_Store .eslintcache .vscode/ -build \ No newline at end of file +build +examples/**/yarn.lock \ No newline at end of file diff --git a/examples/05_typescript/package.json b/examples/05_typescript/package.json index d0a23bdf..3a0c3b08 100644 --- a/examples/05_typescript/package.json +++ b/examples/05_typescript/package.json @@ -3,7 +3,6 @@ "version": "0.1.0", "private": true, "dependencies": { - "@foobar-agency/react-global-state": "latest", "react": "latest", "react-dom": "latest", "react-scripts": "latest" diff --git a/examples/05_typescript/tsconfig.json b/examples/05_typescript/tsconfig.json index a273b0cf..81e44c08 100644 --- a/examples/05_typescript/tsconfig.json +++ b/examples/05_typescript/tsconfig.json @@ -18,7 +18,11 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "@foobar-agency/react-global-state": ["../../lib/esm/index"] + } }, "include": [ "src" diff --git a/package.json b/package.json index 3d4d4468..ce3bba47 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,8 @@ "eslint-config-prettier": "^8.1.0", "eslint-import-resolver-typescript": "^2.5.0", "eslint-plugin-import": "^2.25.2", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0", "jest": "^27.4.7", "jest-localstorage-mock": "^2.4.18", "prettier": "^2.2.1", diff --git a/src/Observable.ts b/src/Observable.ts index 2a5a8fda..b56d9077 100644 --- a/src/Observable.ts +++ b/src/Observable.ts @@ -5,7 +5,7 @@ import { isBrowser } from "./isBrowser" -export class Observable { +export class Observable { private static stateIndex = 0 private static eventOptions: AddEventListenerOptions = { @@ -16,13 +16,13 @@ export class Observable { private readonly eventName = `${Observable.stateIndex++}-global-state-change` - constructor(private _value: S) {} + constructor(private _value: TState) {} get value() { return this._value } - next(value: S) { + next(value: TState) { if (value === this._value) { return } @@ -34,7 +34,7 @@ export class Observable { } } - subscribe(subscriber: (value: S) => void) { + subscribe(subscriber: (value: TState) => void) { const eventListener = () => subscriber(this._value) const eventName = this.eventName diff --git a/src/createGlobalState.ts b/src/createGlobalState.ts index 5685def0..6fb3653e 100644 --- a/src/createGlobalState.ts +++ b/src/createGlobalState.ts @@ -1,4 +1,5 @@ import { SetStateAction } from "react" + import { Observable } from "./Observable" import { isBrowser } from "./isBrowser" import { isEqual } from "./isEqual" @@ -13,11 +14,11 @@ import updater from "./updater" import { createHook } from "./createHook" import { createReadOnlyHook } from "./createReadOnlyHook" -export const createGlobalState = ( - initialState: S, +export const createGlobalState = ( + initialState: TState, options?: GlobalStateOptions -): GlobalState => { - const state$ = new Observable(initialState) +): GlobalState => { + const state$ = new Observable(initialState) if (options?.persistence?.key && isBrowser()) { rehydrate(state$, options?.persistence) @@ -26,7 +27,7 @@ export const createGlobalState = ( const getGlobalState = () => state$.value const setGlobalState = ( - state: SetStateAction, + state: SetStateAction, options?: SetStateOptions ) => { if (options?.deepCompare) { @@ -42,8 +43,9 @@ export const createGlobalState = ( const useReadOnlyState = createReadOnlyHook(state$, state => state) - const createPartialState = (project: (state: S) => PartialState) => - createReadOnlyHook(state$, project) + const createPartialState = ( + project: (state: TState) => PartialState + ) => createReadOnlyHook(state$, project) return { useGlobalState, diff --git a/src/createHook.ts b/src/createHook.ts index 25cf9df5..ec801024 100644 --- a/src/createHook.ts +++ b/src/createHook.ts @@ -1,10 +1,14 @@ import { SetStateAction, useEffect, useState } from "react" + import { Observable } from "./Observable" import { SetStateOptions } from "./types" -export function createHook( - state$: Observable, - setGlobalState: (state: SetStateAction, options?: SetStateOptions) => void +export function createHook( + state$: Observable, + setGlobalState: ( + state: SetStateAction, + options?: SetStateOptions + ) => void ) { return () => { const [state, setState] = useState(state$.value) @@ -18,7 +22,10 @@ export function createHook( * the reason for that is we only subscribe to the state$ if the component is mounted */ const stateValueAfterMount = state$.value - state !== stateValueAfterMount && setState(stateValueAfterMount) + + if (state !== stateValueAfterMount) { + setState(stateValueAfterMount) + } const subscription = state$.subscribe(setState) diff --git a/src/createReadOnlyHook.ts b/src/createReadOnlyHook.ts index 6a29be5d..ff5a8533 100644 --- a/src/createReadOnlyHook.ts +++ b/src/createReadOnlyHook.ts @@ -1,10 +1,11 @@ import { useEffect, useState } from "react" + import { Observable } from "./Observable" import { PartialState } from "./types" -export function createReadOnlyHook( - state$: Observable, - project: (state: S) => PartialState +export function createReadOnlyHook( + state$: Observable, + project: (state: TState) => PartialState ) { return () => { const [state, setState] = useState(project(state$.value)) diff --git a/src/rehydrate.ts b/src/rehydrate.ts index 10359773..bedc338c 100644 --- a/src/rehydrate.ts +++ b/src/rehydrate.ts @@ -3,8 +3,8 @@ import { isEqual } from "./isEqual" import { PersistenceOptions } from "./types" import { Observable } from "./Observable" -export function rehydrate( - state$: Observable, +export function rehydrate( + state$: Observable, options: PersistenceOptions ) { const { key, type } = options @@ -13,7 +13,7 @@ export function rehydrate( ? globalThis.sessionStorage : globalThis.localStorage - const storage = new StorageItem(key, storageLayer) + const storage = new StorageItem(key, storageLayer) const storedValue = storage.get() diff --git a/src/types.ts b/src/types.ts index 80594b28..77b357d6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,17 +13,20 @@ export interface GlobalStateOptions { persistence?: PersistenceOptions } -export type PartialState = Partial | keyof T +export type PartialState = TState | TPartial -export interface GlobalState { +export interface GlobalState { useGlobalState: () => readonly [ - T, - (state: SetStateAction, options?: SetStateOptions) => void + TState, + (state: SetStateAction, options?: SetStateOptions) => void ] - useReadOnlyState: () => PartialState - createPartialState: ( - project: (state: T) => PartialState - ) => () => PartialState - getGlobalState: () => T - setGlobalState: (state: SetStateAction, options?: SetStateOptions) => void + useReadOnlyState: () => PartialState + createPartialState: ( + project: (state: TState) => PartialState + ) => () => PartialState + getGlobalState: () => TState + setGlobalState: ( + state: SetStateAction, + options?: SetStateOptions + ) => void } diff --git a/tsconfig.json b/tsconfig.json index 8a054953..6c921f06 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,7 @@ "es2020", "DOM" ], "paths": { - "@foobaragency/react-global-state": ["src/*"] + "@foobar-agency/react-global-state/*": ["src/*"] } }, "include": ["./src"] diff --git a/yarn.lock b/yarn.lock index 90b62219..a9f81903 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2103,7 +2103,7 @@ array-ify@^1.0.0: resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= -array-includes@^3.1.4: +array-includes@^3.1.3, array-includes@^3.1.4: version "3.1.4" resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz" integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== @@ -2128,6 +2128,15 @@ array.prototype.flat@^1.2.5: define-properties "^1.1.3" es-abstract "^1.19.0" +array.prototype.flatmap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" + integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.19.0" + arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -3072,6 +3081,31 @@ eslint-plugin-import@^2.25.2: resolve "^1.20.0" tsconfig-paths "^3.12.0" +eslint-plugin-react-hooks@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" + integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== + +eslint-plugin-react@^7.28.0: + version "7.28.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz#8f3ff450677571a659ce76efc6d80b6a525adbdf" + integrity sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw== + dependencies: + array-includes "^3.1.4" + array.prototype.flatmap "^1.2.5" + doctrine "^2.1.0" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.0.4" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.0" + object.values "^1.1.5" + prop-types "^15.7.2" + resolve "^2.0.0-next.3" + semver "^6.3.0" + string.prototype.matchall "^4.0.6" + eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" @@ -3179,7 +3213,7 @@ estraverse@^4.1.1: resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0, estraverse@^5.2.0: +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -3804,7 +3838,7 @@ is-cidr@^4.0.2: dependencies: cidr-regex "^3.1.1" -is-core-module@^2.5.0, is-core-module@^2.8.0: +is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== @@ -4562,6 +4596,14 @@ jsonparse@^1.2.0, jsonparse@^1.3.1: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" + integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== + dependencies: + array-includes "^3.1.3" + object.assign "^4.1.2" + just-diff-apply@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-4.0.1.tgz#da89c5a4ccb14aa8873c70e2c3b6695cef45dab5" @@ -4788,7 +4830,7 @@ lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -loose-envify@^1.1.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -5359,6 +5401,32 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" +object.entries@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.fromentries@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.hasown@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" + integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.19.1" + object.values@^1.1.5: version "1.1.5" resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz" @@ -5575,7 +5643,7 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.7: +path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -5701,6 +5769,15 @@ promzard@^0.3.0: dependencies: read "1" +prop-types@^15.7.2: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + psl@^1.1.33: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" @@ -5750,6 +5827,11 @@ react-dom@^17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-is@^17.0.1: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" @@ -5883,6 +5965,14 @@ regenerator-transform@^0.14.2: dependencies: "@babel/runtime" "^7.8.4" +regexp.prototype.flags@^1.3.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" + integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + regexpp@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" @@ -5955,6 +6045,14 @@ resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^2.0.0-next.3: + version "2.0.0-next.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" + integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -6300,6 +6398,20 @@ string-length@^4.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string.prototype.matchall@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" + integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.3.1" + side-channel "^1.0.4" + string.prototype.trimend@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz"