diff --git a/packages/use-segment/src/__tests__/index.tsx b/packages/use-segment/src/__tests__/index.tsx index 9f65aa256..9a02b3bb9 100644 --- a/packages/use-segment/src/__tests__/index.tsx +++ b/packages/use-segment/src/__tests__/index.tsx @@ -11,7 +11,7 @@ const wrapper = writeKey, onError = e => log(e), events = defaultEvents, - }: SegmentProviderProps) => + }: SegmentProviderProps) => ({ children }: { children: ReactNode }) => ( diff --git a/packages/use-segment/src/useSegment.tsx b/packages/use-segment/src/useSegment.tsx index b7bb2bf26..a813bb3bb 100644 --- a/packages/use-segment/src/useSegment.tsx +++ b/packages/use-segment/src/useSegment.tsx @@ -1,7 +1,6 @@ import { Analytics, AnalyticsBrowser } from '@segment/analytics-next' import React, { - FunctionComponent, - ReactElement, + ReactNode, createContext, useContext, useEffect, @@ -9,9 +8,12 @@ import React, { useState, } from 'react' -interface SegmentContextInteface { +type EventFunction = (...args: unknown[]) => Promise +type Events = Record EventFunction> + +interface SegmentContextInterface { analytics: Analytics | undefined - events: Record + events: { [K in keyof T]: ReturnType } writeKey?: string onError?: (err: Error) => void } @@ -23,10 +25,12 @@ const initialContext = { writeKey: undefined, } -const SegmentContext = createContext(initialContext) +const SegmentContext = createContext(initialContext) -export const useSegment = (): SegmentContextInteface => { - const context = useContext(SegmentContext) +export function useSegment(): SegmentContextInterface { + // @ts-expect-error Here we force cast the generic onto the useContext because the context is a + // global variable and cannot be generic + const context = useContext>(SegmentContext) if (context === undefined) { throw new Error('useSegment must be used within a SegmentProvider') } @@ -34,18 +38,19 @@ export const useSegment = (): SegmentContextInteface => { return context } -export type SegmentProviderProps = { +export type SegmentProviderProps = { writeKey?: string onError: (err: Error) => void - events: Record + events: T + children: ReactNode } -const SegmentProvider: FunctionComponent = ({ +function SegmentProvider({ children, writeKey, onError, events, -}): ReactElement => { +}: SegmentProviderProps) { const [analytics, setAnalytics] = useState(undefined) useEffect(() => { @@ -63,13 +68,20 @@ const SegmentProvider: FunctionComponent = ({ } }, [onError, writeKey]) - const value = useMemo( - () => ({ + const value = useMemo>(() => { + const curiedEvents = Object.entries(events).reduce( + (acc, [eventName, eventFn]) => ({ + ...acc, + [eventName]: eventFn(analytics), + }), + {}, + ) as { [K in keyof T]: ReturnType } + + return { analytics, - events, - }), - [analytics, events], - ) + events: curiedEvents, + } + }, [analytics, events]) return ( {children}