Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PrevState typing in TypeScript

I am using a context to store an object for my dialog. I have a function which updates an array stored in the context based on prevState however, TypeScript doesn't like my prevState typing.

Argument of type '(prevState: SourceOrganizationAccount[]) => SourceOrganizationAccount[]' is not assignable to parameter of type 'SourceOrganizationAccount[]'. Type '(prevState: SourceOrganizationAccount[]) => SourceOrganizationAccount[]' is missing the following properties from type 'SourceOrganizationAccount[]': pop, push, concat, join, and 27 more.

Here's my component with the function handleCheckAccountDetailsClick. It complains on this line sourceOrganizationAccounts.setValue((prevState: SourceOrganizationAccount[]) => {. What is wrong with that prevState?

import React from 'react';
import { getAccount } from 'utils';
import {
  SourceOrganizationAccount,
  useImportAccountsContext,
} from '../ImportAccountsContext';

export function ImportAccountsTable() {
  const { sourceOrganizationAccounts } = useImportAccountsContext();

  async function handleCheckAccountDetailsClick(account: SourceOrganizationAccount) {
    const accountDetailsRes = await getAccount();

    if (accountDetailsRes.success) {
      sourceOrganizationAccounts.setValue((prevState: SourceOrganizationAccount[]) => {
        const updatedArray = prevState.map(sourceOrganizationAccount => {
          return sourceOrganizationAccount.locator === account.locator
            ? {
                ...sourceOrganizationAccount,
                ...accountDetailsRes.accountDetails,
              }
            : sourceOrganizationAccount;
        });

        return updatedArray;
      });
    }
  }

  return <>Test</>;
}

My types

export type SourceOrganizationAccount = {
  name: string;
  createdOn: number;
  locator: string;
}

export interface StateVariable<T> {
  value: T;
  setValue: (value: T) => void;
}

export interface ImportAccountsState {
    sourceOrganizationAccounts: StateVariable<SourceOrganizationAccount[]>;
}

const ImportAccountsContext = createContext<ImportAccountsState>(
  {} as ImportAccountsState,
);

export const ImportAccountsProvider = ({ children }: props) => {
  const [sourceOrganizationAccounts, setSourceOrganizationAccounts] = useState<
    SourceOrganizationAccount[]
  >([]);

  const resetContext = useCallback(() => {
    setSourceOrganizationAccounts([]);
  }, [
    setSourceOrganizationAccounts,
  ]);

  const initialState: ImportAccountsState = {
    sourceOrganizationAccounts: {
      value: sourceOrganizationAccounts,
      setValue: setSourceOrganizationAccounts,
    }
  };

  return (
    <ImportAccountsContext.Provider value={initialState}>
      {children}
    </ImportAccountsContext.Provider>
  );
};

export const useImportAccountsContext = () => {
  return useContext<ImportAccountsState>(ImportAccountsContext);
};
like image 366
LazioTibijczyk Avatar asked Jun 17 '26 12:06

LazioTibijczyk


1 Answers

If you check thoroughly your StateVariable<T> type you may notice that setValue field of that type has signature:

setValue: (value: T) => void

While you're trying to feed it instead of a value of type T the value (function) of type: (prevState: T) => T.

To match your function implementation the type StateVariable should be defined as:

interface StateVariable<T> {
  value: T;
  setValue: (cb: (value: T) => T) => void;
}

React exposes special helper types for typing useState dispatch functions: Dispatch<SetStateAction<T>> so you may write it also as:

import { Dispatch, SetStateAction } from 'react'

interface StateVariable<T> {
  value: T
  setValue: Dispatch<SetStateAction<T>>
}
like image 174
aleksxor Avatar answered Jun 21 '26 11:06

aleksxor



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!