Skip to content

Commit

Permalink
Merge pull request #1887 from reduxjs/feature/v8-types-updates
Browse files Browse the repository at this point in the history
  • Loading branch information
markerikson committed Apr 10, 2022
2 parents f965039 + 857311d commit 1659df0
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 139 deletions.
12 changes: 7 additions & 5 deletions package.json
Expand Up @@ -43,6 +43,9 @@
"react": "^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"react-dom": {
"optional": true
},
Expand Down Expand Up @@ -81,11 +84,10 @@
"@testing-library/react-hooks": "^3.4.2",
"@testing-library/react-native": "^7.1.0",
"@types/object-assign": "^4.0.30",
"@types/react": "^17.0.43",
"@types/react-dom": "^17.0.14",
"@types/react-is": "^17.0.3",
"@types/react-native": "^0.64.12",
"@types/react-redux": "^7.1.18",
"@types/react": "^18",
"@types/react-dom": "^18",
"@types/react-is": "^17",
"@types/react-native": "^0.67.4",
"@typescript-eslint/eslint-plugin": "^4.28.0",
"@typescript-eslint/parser": "^4.28.0",
"babel-eslint": "^10.1.0",
Expand Down
17 changes: 12 additions & 5 deletions src/components/connect.tsx
Expand Up @@ -8,7 +8,6 @@ import type { Store, Dispatch, Action, AnyAction } from 'redux'
import type {
AdvancedComponentDecorator,
ConnectedComponent,
DefaultRootState,
InferableComponentEnhancer,
InferableComponentEnhancerWithProps,
ResolveThunks,
Expand Down Expand Up @@ -246,7 +245,7 @@ export type ConnectedProps<TConnector> =
: never

export interface ConnectOptions<
State = DefaultRootState,
State = unknown,
TStateProps = {},
TOwnProps = {},
TMergedProps = {}
Expand Down Expand Up @@ -289,7 +288,7 @@ export interface ConnectOptions<
* @param mergeProps
* @param options
*/
export interface Connect<DefaultState = DefaultRootState> {
export interface Connect<DefaultState = unknown> {
// tslint:disable:no-unnecessary-generics
(): InferableComponentEnhancer<DispatchProp>

Expand Down Expand Up @@ -453,7 +452,7 @@ function connect<
TDispatchProps = {},
TOwnProps = {},
TMergedProps = {},
State = DefaultRootState
State = unknown
>(
mapStateToProps?: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps?: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
Expand Down Expand Up @@ -527,12 +526,20 @@ function connect<

const displayName = `Connect(${wrappedComponentName})`

const selectorFactoryOptions: SelectorFactoryOptions<any, any, any, any> = {
const selectorFactoryOptions: SelectorFactoryOptions<
any,
any,
any,
any,
State
> = {
shouldHandleStateChanges,
displayName,
wrappedComponentName,
WrappedComponent,
// @ts-ignore
initMapStateToProps,
// @ts-ignore
initMapDispatchToProps,
// @ts-ignore
initMergeProps,
Expand Down
34 changes: 11 additions & 23 deletions src/connect/selectorFactory.ts
@@ -1,6 +1,6 @@
import type { Dispatch, Action } from 'redux'
import verifySubselectors from './verifySubselectors'
import type { DefaultRootState, EqualityFn } from '../types'
import type { EqualityFn } from '../types'

export type SelectorFactory<S, TProps, TOwnProps, TFactoryOptions> = (
dispatch: Dispatch<Action>,
Expand All @@ -13,26 +13,17 @@ export type Selector<S, TProps, TOwnProps = null> = TOwnProps extends
? (state: S) => TProps
: (state: S, ownProps: TOwnProps) => TProps

export type MapStateToProps<
TStateProps,
TOwnProps,
State = DefaultRootState
> = (state: State, ownProps: TOwnProps) => TStateProps
export type MapStateToProps<TStateProps, TOwnProps, State = unknown> = (
state: State,
ownProps: TOwnProps
) => TStateProps

export type MapStateToPropsFactory<
TStateProps,
TOwnProps,
State = DefaultRootState
> = (
export type MapStateToPropsFactory<TStateProps, TOwnProps, State = unknown> = (
initialState: State,
ownProps: TOwnProps
) => MapStateToProps<TStateProps, TOwnProps, State>

export type MapStateToPropsParam<
TStateProps,
TOwnProps,
State = DefaultRootState
> =
export type MapStateToPropsParam<TStateProps, TOwnProps, State = unknown> =
| MapStateToPropsFactory<TStateProps, TOwnProps, State>
| MapStateToProps<TStateProps, TOwnProps, State>
| null
Expand Down Expand Up @@ -66,10 +57,7 @@ export type MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps> = (
ownProps: TOwnProps
) => TMergedProps

interface PureSelectorFactoryComparisonOptions<
TOwnProps,
State = DefaultRootState
> {
interface PureSelectorFactoryComparisonOptions<TOwnProps, State = unknown> {
areStatesEqual: EqualityFn<State>
areOwnPropsEqual: EqualityFn<TOwnProps>
areStatePropsEqual: EqualityFn<unknown>
Expand All @@ -81,7 +69,7 @@ export function pureFinalPropsSelectorFactory<
TOwnProps,
TDispatchProps,
TMergedProps,
State = DefaultRootState
State = unknown
>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State> & {
dependsOnOwnProps: boolean
Expand Down Expand Up @@ -180,7 +168,7 @@ export interface SelectorFactoryOptions<
TOwnProps,
TDispatchProps,
TMergedProps,
State = DefaultRootState
State = unknown
> extends PureSelectorFactoryComparisonOptions<TOwnProps, State> {
initMapStateToProps: (
dispatch: Dispatch,
Expand All @@ -207,7 +195,7 @@ export default function finalPropsSelectorFactory<
TOwnProps,
TDispatchProps,
TMergedProps,
State = DefaultRootState
State = unknown
>(
dispatch: Dispatch<Action>,
{
Expand Down
2 changes: 1 addition & 1 deletion src/connect/wrapMapToProps.ts
Expand Up @@ -4,7 +4,7 @@ import { FixTypeLater } from '../types'
import verifyPlainObject from '../utils/verifyPlainObject'

type AnyState = { [key: string]: any }
type StateOrDispatch<S = AnyState> = S | Dispatch
type StateOrDispatch<S extends AnyState = AnyState> = S | Dispatch

type AnyProps = { [key: string]: any }

Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useDispatch.ts
Expand Up @@ -6,7 +6,6 @@ import {
ReactReduxContextValue,
} from '../components/Context'
import { useStore as useDefaultStore, createStoreHook } from './useStore'
import { RootStateOrAny } from '../types'

/**
* Hook factory, which creates a `useDispatch` hook bound to a given context.
Expand All @@ -15,7 +14,7 @@ import { RootStateOrAny } from '../types'
* @returns {Function} A `useDispatch` hook bound to the specified context.
*/
export function createDispatchHook<
S = RootStateOrAny,
S = unknown,
A extends Action = AnyAction
// @ts-ignore
>(context?: Context<ReactReduxContextValue<S, A>> = ReactReduxContext) {
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useSelector.ts
Expand Up @@ -2,7 +2,7 @@ import { useContext, useDebugValue } from 'react'

import { useReduxContext as useDefaultReduxContext } from './useReduxContext'
import { ReactReduxContext } from '../components/Context'
import type { DefaultRootState, EqualityFn } from '../types'
import type { EqualityFn } from '../types'
import type { uSESWS } from '../utils/useSyncExternalStore'
import { notInitialized } from '../utils/useSyncExternalStore'

Expand All @@ -21,7 +21,7 @@ const refEquality: EqualityFn<any> = (a, b) => a === b
*/
export function createSelectorHook(
context = ReactReduxContext
): <TState = DefaultRootState, Selected = unknown>(
): <TState = unknown, Selected = unknown>(
selector: (state: TState) => Selected,
equalityFn?: EqualityFn<Selected>
) => Selected {
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useStore.ts
Expand Up @@ -5,7 +5,6 @@ import {
ReactReduxContextValue,
} from '../components/Context'
import { useReduxContext as useDefaultReduxContext } from './useReduxContext'
import { RootStateOrAny } from '../types'

/**
* Hook factory, which creates a `useStore` hook bound to a given context.
Expand All @@ -14,7 +13,7 @@ import { RootStateOrAny } from '../types'
* @returns {Function} A `useStore` hook bound to the specified context.
*/
export function createStoreHook<
S = RootStateOrAny,
S = unknown,
A extends BasicAction = AnyAction
// @ts-ignore
>(context?: Context<ReactReduxContextValue<S, A>> = ReactReduxContext) {
Expand Down
10 changes: 0 additions & 10 deletions src/types.ts
Expand Up @@ -10,17 +10,7 @@ export type FixTypeLater = any

export type EqualityFn<T> = (a: T, b: T) => boolean

/**
* This interface can be augmented by users to add default types for the root state when
* using `react-redux`.
* Use module augmentation to append your own type definition in a your_custom_type.d.ts file.
* https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
*/
// tslint:disable-next-line:no-empty-interface
export interface DefaultRootState {}

export type AnyIfEmpty<T extends object> = keyof T extends never ? any : T
export type RootStateOrAny = AnyIfEmpty<DefaultRootState>

export type DistributiveOmit<T, K extends keyof T> = T extends unknown
? Omit<T, K>
Expand Down
1 change: 1 addition & 0 deletions test/components/connect.spec.tsx
Expand Up @@ -2018,6 +2018,7 @@ describe('React', () => {
return false
}
render() {
// @ts-ignore don't care about "children" errors
return this.props.children
}
}
Expand Down
3 changes: 1 addition & 2 deletions test/typetests/connect-options-and-issues.tsx
Expand Up @@ -31,7 +31,6 @@ import {
createSelectorHook,
createStoreHook,
TypedUseSelectorHook,
DefaultRootState,
} from '../../src/index'

import { expectType } from '../typeTestHelpers'
Expand Down Expand Up @@ -837,7 +836,7 @@ function testRef() {
function testConnectDefaultState() {
connect((state) => {
const s = state
expectType<DefaultRootState>(s)
expectType<unknown>(s)
return state
})

Expand Down
42 changes: 23 additions & 19 deletions test/typetests/hooks.tsx
Expand Up @@ -2,7 +2,7 @@

import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { Store, Dispatch, configureStore } from '@reduxjs/toolkit'
import { Store, Dispatch, configureStore, AnyAction } from '@reduxjs/toolkit'
import {
connect,
ConnectedProps,
Expand Down Expand Up @@ -34,6 +34,8 @@ import {
fetchCount,
} from './counterApp'

import { expectType } from '../typeTestHelpers'

function preTypedHooksSetup() {
// Standard hooks setup
const useAppDispatch = () => useDispatch<AppDispatch>()
Expand Down Expand Up @@ -147,8 +149,7 @@ function testUseSelector() {
useSelector(selector, 'a')
useSelector(selector, (l, r) => l === r)
useSelector(selector, (l, r) => {
// $ExpectType { counter: number; active: string; }
l
expectType<{ counter: number; active: string }>(l)
return l === r
})

Expand All @@ -169,12 +170,11 @@ function testUseSelector() {

const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector

// $ExpectType string
const r = useTypedSelector((state) => {
// $ExpectType RootState
state
expectType<RootState>(state)
return state.property
})
expectType<string>(r)
}

function testUseStore() {
Expand All @@ -188,7 +188,7 @@ function testUseStore() {

const untypedStore = useStore()
const state = untypedStore.getState()
state.things.stuff.anything // any by default
expectType<unknown>(state)

const typedStore = useStore<TypedState, TypedAction>()
const typedState = typedStore.getState()
Expand All @@ -211,18 +211,22 @@ function testCreateHookFunctions() {
>(null as any)

// No context tests
// $ExpectType () => Dispatch<AnyAction>
createDispatchHook()
// $ExpectType <Selected extends unknown>(selector: (state: any) => Selected, equalityFn?: ((previous: Selected, next: Selected) => boolean) | undefined) => Selected
createSelectorHook()
// $ExpectType () => Store<any, AnyAction>
createStoreHook()
expectType<() => Dispatch<AnyAction>>(createDispatchHook())
expectType<
<Selected extends unknown>(
selector: (state: any) => Selected,
equalityFn?: ((previous: Selected, next: Selected) => boolean) | undefined
) => Selected
>(createSelectorHook())
expectType<() => Store<any, AnyAction>>(createStoreHook())

// With context tests
// $ExpectType () => Dispatch<RootAction>
createDispatchHook(Context)
// $ExpectType <Selected extends unknown>(selector: (state: RootState) => Selected, equalityFn?: ((previous: Selected, next: Selected) => boolean) | undefined) => Selected
createSelectorHook(Context)
// $ExpectType () => Store<RootState, RootAction>
createStoreHook(Context)
expectType<() => Dispatch<RootAction>>(createDispatchHook(Context))
expectType<
<Selected extends unknown>(
selector: (state: RootState) => Selected,
equalityFn?: ((previous: Selected, next: Selected) => boolean) | undefined
) => Selected
>(createSelectorHook(Context))
expectType<() => Store<RootState, RootAction>>(createStoreHook(Context))
}

0 comments on commit 1659df0

Please sign in to comment.