diff --git a/jest.config.js b/jest.config.js index a963d5fff..2e82e40f9 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,14 +1,9 @@ -const { default: tsJestPreset } = require('ts-jest') - const defaults = { - ...tsJestPreset, coverageDirectory: './coverage/', collectCoverage: true, testURL: 'http://localhost', } - -const testFolderPath = (folderName) => - `/test/${folderName}/**/*.{js,ts,tsx}` +const testFolderPath = (folderName) => `/test/${folderName}/**/*.js` const NORMAL_TEST_FOLDERS = ['components', 'hooks', 'integration', 'utils'] @@ -18,6 +13,16 @@ const standardConfig = { testMatch: NORMAL_TEST_FOLDERS.map(testFolderPath), } +const tsTestFolderPath = (folderName) => + `/test/${folderName}/**/*.{ts,tsx}` + +const tsStandardConfig = { + ...defaults, + displayName: 'ReactDOM', + preset: 'ts-jest', + testMatch: NORMAL_TEST_FOLDERS.map(tsTestFolderPath), +} + const rnConfig = { ...defaults, displayName: 'React Native', @@ -29,5 +34,5 @@ const rnConfig = { } module.exports = { - projects: [standardConfig, rnConfig], + projects: [tsStandardConfig, standardConfig, rnConfig], } diff --git a/package.json b/package.json index 88d5c1ff1..433876815 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "rimraf": "^3.0.2", "rollup": "^2.32.1", "rollup-plugin-terser": "^7.0.2", - "ts-jest": "^27.0.3", + "ts-jest": "26.5.6", "typescript": "^4.3.4" }, "browserify": { diff --git a/src/components/Provider.tsx b/src/components/Provider.tsx index 90a04b83e..ffe9197fa 100644 --- a/src/components/Provider.tsx +++ b/src/components/Provider.tsx @@ -15,7 +15,7 @@ export interface ProviderProps { * 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/connect/wrapMapToProps.ts b/src/connect/wrapMapToProps.ts index be02a4918..a897ddbda 100644 --- a/src/connect/wrapMapToProps.ts +++ b/src/connect/wrapMapToProps.ts @@ -47,7 +47,7 @@ export function wrapMapToPropsConstant( // A length of zero is assumed to mean mapToProps is getting args via arguments or ...args and // therefore not reporting its length accurately.. export function getDependsOnOwnProps(mapToProps: MapToProps) { - return mapToProps?.dependsOnOwnProps + return mapToProps.dependsOnOwnProps ? Boolean(mapToProps.dependsOnOwnProps) : mapToProps.length !== 1 } diff --git a/src/types.ts b/src/types.ts index affe26c22..a291b83a4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -272,6 +272,6 @@ export type ResolveArrayThunks> = export interface TypedUseSelectorHook { ( selector: (state: TState) => TSelected, - equalityFn?: (left: TSelected, right: TSelected) => boolean + equalityFn?: EqualityFn ): TSelected } diff --git a/test/components/hooks.spec.tsx b/test/components/hooks.spec.tsx index 219ec6795..9fa082fd6 100644 --- a/test/components/hooks.spec.tsx +++ b/test/components/hooks.spec.tsx @@ -43,7 +43,7 @@ describe('React', () => { const mapStateSpy1 = jest.fn() const renderSpy1 = jest.fn() - let component1StateList + let component1StateList: number[] const component1Decorator = connect< Omit, @@ -77,23 +77,31 @@ describe('React', () => { const mapStateSpy2 = jest.fn() const renderSpy2 = jest.fn() - interface Component2PropsType { - mappedProp: Array + interface Component2Tstate { + mappedProp: string[] } const component2Decorator = connect< - Component2PropsType, + Component2Tstate, unknown, Omit, RootStateType - >((state, ownProps) => { - mapStateSpy2() - - return { - mappedProp: ownProps.list.map((id) => state.byId[id]), + >( + ( + state: RootStateType, + ownProps: Omit + ): Component2Tstate => { + mapStateSpy2() + + return { + mappedProp: ownProps.list.map((id) => state.byId[id]), + } } - }) + ) + interface Component2PropsType { + list: number[] + } - const component2 = (props) => { + const component2 = (props: Component2PropsType) => { renderSpy2() expect(props.list).toBe(component1StateList) diff --git a/test/hooks/useDispatch.spec.tsx b/test/hooks/useDispatch.spec.tsx index 32143cb46..d475ac20d 100644 --- a/test/hooks/useDispatch.spec.tsx +++ b/test/hooks/useDispatch.spec.tsx @@ -7,9 +7,10 @@ import { createDispatchHook, } from '../../src/index' import type { ProviderProps } from '../../src/' +import type { ReactReduxContextValue } from '../../src/components/Context' -const store = createStore((c: number): number => c + 1) -const store2 = createStore((c: number): number => c + 2) +const store = createStore((c: number = 1): number => c + 1) +const store2 = createStore((c: number = 1): number => c + 2) describe('React', () => { describe('hooks', () => { @@ -27,7 +28,8 @@ describe('React', () => { }) describe('createDispatchHook', () => { it("returns the correct store's dispatch function", () => { - const nestedContext = React.createContext(null) + const nestedContext = + React.createContext(null) const useCustomDispatch = createDispatchHook(nestedContext) const { result } = renderHook(() => useDispatch(), { // eslint-disable-next-line react/prop-types diff --git a/test/hooks/useSelector.spec.tsx b/test/hooks/useSelector.spec.tsx index 587f215e0..b8c7697f4 100644 --- a/test/hooks/useSelector.spec.tsx +++ b/test/hooks/useSelector.spec.tsx @@ -11,11 +11,12 @@ import { connect, createSelectorHook, } from '../../src/index' -import type { FunctionComponent } from 'react' import { useReduxContext } from '../../src/hooks/useReduxContext' +import type { FunctionComponent, DispatchWithoutAction, ReactNode } from 'react' import type { Store, AnyAction } from 'redux' import type { ProviderProps, TypedUseSelectorHook } from '../../src/' import type { Subscription } from '../../src/utils/Subscription' +import type { ReactReduxContextValue } from '../../src/components/Context' describe('React', () => { describe('hooks', () => { @@ -24,7 +25,7 @@ describe('React', () => { count: number } let normalStore: Store - let renderedItems = [] + let renderedItems: any[] = [] type RootState = ReturnType let useNormalSelector: TypedUseSelectorHook = useSelector @@ -56,7 +57,8 @@ describe('React', () => { }) it('selects the state and renders the component when the store updates', () => { - const selector: jest.Mock = jest.fn( + type MockParams = [NormalStateType] + const selector: jest.Mock = jest.fn( (s) => s.count ) @@ -80,7 +82,7 @@ describe('React', () => { describe('lifecycle interactions', () => { it('always uses the latest state', () => { - const store = createStore((c: number): number => c + 1, -1) + const store = createStore((c: number = 1): number => c + 1, -1) const Comp = () => { const selector = useCallback((c: number): number => c + 1, []) @@ -106,7 +108,7 @@ describe('React', () => { let rootSubscription: Subscription const Parent = () => { - const { subscription } = useReduxContext() + const { subscription } = useReduxContext() as ReactReduxContextValue rootSubscription = subscription const count = useNormalSelector((s) => s.count) return count === 1 ? : null @@ -122,11 +124,11 @@ describe('React', () => { ) - + // @ts-ignore ts(2454) expect(rootSubscription.getListeners().get().length).toBe(1) normalStore.dispatch({ type: '' }) - + // @ts-ignore ts(2454) expect(rootSubscription.getListeners().get().length).toBe(2) }) @@ -134,7 +136,7 @@ describe('React', () => { let rootSubscription: Subscription const Parent = () => { - const { subscription } = useReduxContext() + const { subscription } = useReduxContext() as ReactReduxContextValue rootSubscription = subscription const count = useNormalSelector((s) => s.count) return count === 0 ? : null @@ -150,11 +152,11 @@ describe('React', () => { ) - + // @ts-ignore ts(2454) expect(rootSubscription.getListeners().get().length).toBe(2) normalStore.dispatch({ type: '' }) - + // @ts-ignore ts(2454) expect(rootSubscription.getListeners().get().length).toBe(1) }) @@ -183,7 +185,7 @@ describe('React', () => { }) it('works properly with memoized selector with dispatch in Child useLayoutEffect', () => { - const store = createStore((c: number): number => c + 1, -1) + const store = createStore((c: number = 1): number => c + 1, -1) const Comp = () => { const selector = useCallback((c: number): number => c, []) @@ -282,7 +284,7 @@ describe('React', () => { it('uses the latest selector', () => { let selectorId = 0 - let forceRender + let forceRender: DispatchWithoutAction const Comp = () => { const [, f] = useReducer((c) => c + 1, 0) @@ -301,7 +303,9 @@ describe('React', () => { expect(renderedItems).toEqual([0]) - rtl.act(forceRender) + rtl.act(() => { + forceRender() + }) expect(renderedItems).toEqual([0, 1]) rtl.act(() => { @@ -309,7 +313,9 @@ describe('React', () => { }) expect(renderedItems).toEqual([0, 1]) - rtl.act(forceRender) + rtl.act(() => { + forceRender() + }) expect(renderedItems).toEqual([0, 1, 2]) }) @@ -503,8 +509,8 @@ describe('React', () => { }) describe('createSelectorHook', () => { - let defaultStore - let customStore + let defaultStore: Store + let customStore: Store type StateType = { count: number } @@ -519,7 +525,8 @@ describe('React', () => { }) it('subscribes to the correct store', () => { - const nestedContext = React.createContext(null) + const nestedContext = + React.createContext(null) const useCustomSelector = createSelectorHook(nestedContext) let defaultCount = null let customCount = null @@ -531,7 +538,10 @@ describe('React', () => { defaultCount = count return <>{children} } - const DisplayCustomCount = ({ children = null }) => { + interface DisplayCustomCountType { + children: ReactNode + } + const DisplayCustomCount = ({ children }: DisplayCustomCountType) => { const count = useCustomSelector(getCount) customCount = count return <>{children} diff --git a/test/typetests/react-redux-types.typetest.tsx b/test/typetests/react-redux-types.typetest.tsx index 26142b0bf..201ddfdf9 100644 --- a/test/typetests/react-redux-types.typetest.tsx +++ b/test/typetests/react-redux-types.typetest.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars, no-inner-declarations */ import { Component, ReactElement } from 'react' -import * as React from 'react' -import * as ReactDOM from 'react-dom' +import React from 'react' +import ReactDOM from 'react-dom' import { Store, Dispatch, bindActionCreators, AnyAction } from 'redux' import { connect, Provider, ConnectedProps } from '../../src/index' import { expectType } from '../typeTestHelpers' diff --git a/tsconfig.json b/tsconfig.json index d4a4611a4..d637ffe8b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,8 +11,9 @@ "declaration": true, "emitDeclarationOnly": true, "outDir": "./es", - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "experimentalDecorators":true }, - "include": ["src/**/*", "types"], + "include": ["src/**/*", "test/**/*", "types"], "exclude": ["node_modules", "dist"] } diff --git a/types/index.d.ts b/types/index.d.ts index 998e1d632..b27ede89d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,16 +1,4 @@ /* eslint-disable no-unused-vars */ -declare module 'react-dom' { - export function unstable_batchedUpdates( - callback: (a: A, b: B) => any, - a: A, - b: B - ): void - export function unstable_batchedUpdates( - callback: (a: A) => any, - a: A - ): void - export function unstable_batchedUpdates(callback: () => any): void -} declare module 'react-native' { export function unstable_batchedUpdates( diff --git a/yarn.lock b/yarn.lock index 8cfea03de..c08da2d54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3571,9 +3571,9 @@ __metadata: linkType: hard "@types/normalize-package-data@npm:^2.4.0": - version: 2.4.0 - resolution: "@types/normalize-package-data@npm:2.4.0" - checksum: 6d077e73be7ac6227b678829c7bd765607136cdef537fd4ee7f368d9302a651aea924254d69826663322048436d90d6e7c679c9aa99c4824a687c568aab8ce4f + version: 2.4.1 + resolution: "@types/normalize-package-data@npm:2.4.1" + checksum: d7bb5756003a5dbf3ea1ee24ee336c036f3670a7f1ca2c8c840b5ba8fdf4b7063f8d8df16ec0427f622cc97e1c44710f089720d7caa521a5f4ec6f4073c69261 languageName: node linkType: hard @@ -3599,9 +3599,9 @@ __metadata: linkType: hard "@types/prettier@npm:^2.0.0": - version: 2.3.1 - resolution: "@types/prettier@npm:2.3.1" - checksum: 62ddbb1ba05d0df97fe49536e0d5409ea76d45cd2f6de062ff351d049e667b77010d2e912733d5d3255829fa1958c684a059e619f9d81e2ba9f27a6204a06149 + version: 2.3.2 + resolution: "@types/prettier@npm:2.3.2" + checksum: 7b425386aaf3b03fa63382ed1aceff367477ef9a52a2705978bfb1495fa1d8795316e1ab84671f6c8c5920de59a33d1567d837b9eb033996983efdfdbce84cb3 languageName: node linkType: hard @@ -5606,7 +5606,7 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^3.0.0, ci-info@npm:^3.1.1": +"ci-info@npm:^3.0.0": version: 3.2.0 resolution: "ci-info@npm:3.2.0" checksum: d4a898d60111d00f2b7a06a349162971fe0603aefa208fe8d1343ce9e93c48e3d37311c47211d5c9040d25b43038c817588e5b7d8eab5d17b00aec49c7b5fade @@ -9694,17 +9694,6 @@ __metadata: languageName: node linkType: hard -"is-ci@npm:^3.0.0": - version: 3.0.0 - resolution: "is-ci@npm:3.0.0" - dependencies: - ci-info: ^3.1.1 - bin: - is-ci: bin.js - checksum: 1e26d3ba6634ebee83f9d22f260354c5d950eada4d609c30cc2642069f8ba52f3aeb4c9bbf8099aaf04a2f44a1ed7beef2a24485f988753c8c078a57e9b3a2fd - languageName: node - linkType: hard - "is-color-stop@npm:^1.1.0": version: 1.1.0 resolution: "is-color-stop@npm:1.1.0" @@ -10711,7 +10700,7 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^26.6.2": +"jest-util@npm:^26.1.0, jest-util@npm:^26.6.2": version: 26.6.2 resolution: "jest-util@npm:26.6.2" dependencies: @@ -10725,20 +10714,6 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^27.0.0": - version: 27.0.6 - resolution: "jest-util@npm:27.0.6" - dependencies: - "@jest/types": ^27.0.6 - "@types/node": "*" - chalk: ^4.0.0 - graceful-fs: ^4.2.4 - is-ci: ^3.0.0 - picomatch: ^2.2.3 - checksum: a62ab3304ad58eb5fa130d66680d987890fca8c0505857a1b8bbcc8cf1de35eb3b82e19bdc5084dd10f68b3ce373234723f57f6e83781d4a4f66be1b647b488d - languageName: node - linkType: hard - "jest-validate@npm:^24.9.0": version: 24.9.0 resolution: "jest-validate@npm:24.9.0" @@ -14561,7 +14536,7 @@ __metadata: rimraf: ^3.0.2 rollup: ^2.32.1 rollup-plugin-terser: ^7.0.2 - ts-jest: ^27.0.3 + ts-jest: 26.5.6 typescript: ^4.3.4 peerDependencies: react: ^16.8.3 || ^17 @@ -16963,14 +16938,14 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:^27.0.3": - version: 27.0.3 - resolution: "ts-jest@npm:27.0.3" +"ts-jest@npm:26.5.6": + version: 26.5.6 + resolution: "ts-jest@npm:26.5.6" dependencies: bs-logger: 0.x buffer-from: 1.x fast-json-stable-stringify: 2.x - jest-util: ^27.0.0 + jest-util: ^26.1.0 json5: 2.x lodash: 4.x make-error: 1.x @@ -16978,11 +16953,11 @@ __metadata: semver: 7.x yargs-parser: 20.x peerDependencies: - jest: ^27.0.0 + jest: ">=26 <27" typescript: ">=3.8 <5.0" bin: ts-jest: cli.js - checksum: a63f3a8620a16335d745f22377a9cc118129d28a5b122c609a7c6aabbb8048c85733c771a0dd39b136e8a75401473409452bdd3c5b9e3b85317c2e3f3ac03267 + checksum: fd32a8b256091d45d850c491fd090f74a368d44bccc8fedfa0dd074757727e7f07621eb2a69ebf081428f44a357a879237a2cf0aef970896410d454d0bf87ac6 languageName: node linkType: hard