Skip to content

Commit 2fc1568

Browse files
authored
ref(react): Use inline types to avoid redux dependency (#2768)
1 parent 7d7f0db commit 2fc1568

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- [react] feat: Add instrumentation for React Router v3 (#2759)
77
- [apm/tracing] fix: Make sure fetch requests are being timed correctly (#2772)
88
- [apm/tracing] fix: Make sure pageload transactions start timestamps are correctly generated (#2773)
9+
- [react] ref: Use inline types to avoid redux dependency. (#2768)
910

1011
## 5.20.0
1112

packages/react/src/redux.ts

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,60 @@
11
// @flow
22
import { configureScope } from '@sentry/minimal';
33
import { Scope } from '@sentry/types';
4-
import { Action, AnyAction, PreloadedState, Reducer, StoreEnhancer, StoreEnhancerStoreCreator } from 'redux';
4+
5+
interface Action<T = any> {
6+
type: T;
7+
}
8+
9+
interface AnyAction extends Action {
10+
[extraProps: string]: any;
11+
}
12+
13+
type Reducer<S = any, A extends Action = AnyAction> = (state: S | undefined, action: A) => S;
14+
15+
type Dispatch<A extends Action = AnyAction> = <T extends A>(action: T, ...extraArgs: any[]) => T;
16+
17+
type ExtendState<State, Extension> = [Extension] extends [never] ? State : State & Extension;
18+
19+
type Unsubscribe = () => void;
20+
21+
interface Store<S = any, A extends Action = AnyAction, StateExt = never, Ext = {}> {
22+
dispatch: Dispatch<A>;
23+
getState(): S;
24+
subscribe(listener: () => void): Unsubscribe;
25+
replaceReducer<NewState, NewActions extends Action>(
26+
nextReducer: Reducer<NewState, NewActions>,
27+
): Store<ExtendState<NewState, StateExt>, NewActions, StateExt, Ext> & Ext;
28+
}
29+
30+
declare const $CombinedState: unique symbol;
31+
32+
type CombinedState<S> = { readonly [$CombinedState]?: undefined } & S;
33+
34+
type PreloadedState<S> = Required<S> extends {
35+
[$CombinedState]: undefined;
36+
}
37+
? S extends CombinedState<infer S1>
38+
? { [K in keyof S1]?: S1[K] extends object ? PreloadedState<S1[K]> : S1[K] }
39+
: never
40+
: { [K in keyof S]: S[K] extends string | number | boolean | symbol ? S[K] : PreloadedState<S[K]> };
41+
42+
type StoreEnhancer<Ext = {}, StateExt = never> = (
43+
next: StoreEnhancerStoreCreator<Ext, StateExt>,
44+
) => StoreEnhancerStoreCreator<Ext, StateExt>;
45+
46+
type StoreEnhancerStoreCreator<Ext = {}, StateExt = never> = <S = any, A extends Action = AnyAction>(
47+
reducer: Reducer<S, A>,
48+
preloadedState?: PreloadedState<S>,
49+
) => Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext;
550

651
export interface SentryEnhancerOptions {
752
/**
853
* Transforms the state before attaching it to an event.
954
* Use this to remove any private data before sending it to Sentry.
1055
* Return null to not attach the state.
1156
*/
12-
stateTransformer(state: any | undefined): any | null;
57+
stateTransformer<S>(state: S | undefined): (S & any) | null;
1358
/**
1459
* Transforms the action before sending it as a breadcrumb.
1560
* Use this to remove any private data before sending it to Sentry.
@@ -19,7 +64,7 @@ export interface SentryEnhancerOptions {
1964
/**
2065
* Called on every state update, configure the Sentry Scope with the redux state.
2166
*/
22-
configureScopeWithState?(scope: Scope, state: any): void;
67+
configureScopeWithState?<S>(scope: Scope, state: S): void;
2368
}
2469

2570
const ACTION_BREADCRUMB_CATEGORY = 'redux.action';
@@ -29,9 +74,14 @@ const STATE_CONTEXT_KEY = 'redux.state';
2974
const defaultOptions: SentryEnhancerOptions = {
3075
actionTransformer: action => action,
3176
// tslint:disable-next-line: no-unsafe-any
32-
stateTransformer: state => state,
77+
stateTransformer: state => state || null,
3378
};
3479

80+
/**
81+
* Creates an enhancer that would be passed to Redux's createStore to log actions and the latest state to Sentry.
82+
*
83+
* @param enhancerOptions Options to pass to the enhancer
84+
*/
3585
function createReduxEnhancer(enhancerOptions?: Partial<SentryEnhancerOptions>): StoreEnhancer {
3686
const options = {
3787
...defaultOptions,
@@ -59,6 +109,7 @@ function createReduxEnhancer(enhancerOptions?: Partial<SentryEnhancerOptions>):
59109

60110
/* Set latest state to scope */
61111
const transformedState = options.stateTransformer(newState);
112+
// tslint:disable-next-line: strict-type-predicates
62113
if (typeof transformedState !== 'undefined' && transformedState !== null) {
63114
// tslint:disable-next-line: no-unsafe-any
64115
scope.setContext(STATE_CONTEXT_KEY, transformedState);

0 commit comments

Comments
 (0)