Gurkiran Singh
Gurkiran Singh

Reputation: 319

Type '{}' is missing the following properties from type - TS error

In the return of useUser() function, I keep getting this typescript error.

Type '{}' is missing the following properties from type 'IUseUser': userState, dispatchUserContext

import { useReducer, useContext, createContext, FunctionComponent } from 'react';

export interface EditProfileFields {
  phone: string;
  city: string;
  description: string;
  startDate: string;
  endDate: string;
  priceRate: string;
}

export interface IUserContext extends EditProfileFields {
  coverImg: string;
  profileImg: string;
  isDogSitter: boolean;
  isAvailable: boolean;
}

type Action =
  | { type: 'UPLOAD_PROFILE'; profileImg: string }
  | { type: 'UPLOAD_BACKGROUND'; coverImg: string }
  | { type: 'EMPTY_IMAGES' }
  | { type: 'SET_IS_DOG_SITTER' }
  | { type: 'UPDATE_EDIT_PROFILE_FIELDS'; fields: EditProfileFields };

type Dispatch = (action: Action) => void;

export interface IUseUser {
  userState: IUserContext;
  dispatchUserContext: Dispatch;
}

const userReducer = (state: IUserContext, action: Action) => {
  switch (action.type) {
    case 'UPLOAD_PROFILE':
      return { ...state, profileImg: action.profileImg };
    case 'UPLOAD_BACKGROUND':
      return { ...state, coverImg: action.coverImg };
    case 'EMPTY_IMAGES':
      return { ...state, coverImg: '', profileImg: '' };
    case 'SET_IS_DOG_SITTER':
      return { ...state, isDogSitter: true };
    case 'UPDATE_EDIT_PROFILE_FIELDS':
      const { startDate, endDate, ...otherFields } = action.fields;
      return {
        ...state,
        startDate: startDate !== null ? startDate.substring(0, 10) : '',
        endDate: endDate !== null ? endDate.substring(0, 10) : '',
        ...otherFields,
      };
    default:
      throw new Error();
  }
};

const UserContext = createContext({});

const UserProvider: FunctionComponent = ({ children }): JSX.Element => {
  const [userState, dispatchUserContext] = useReducer(userReducer, {
    coverImg: '',
    profileImg: '',
    isDogSitter: false,
    isAvailable: false,
    phone: '',
    city: '',
    description: '',
    startDate: '',
    endDate: '',
    priceRate: '',
  });
  return <UserContext.Provider value={{ userState, dispatchUserContext }}>{children}</UserContext.Provider>;
};

function useUser(): IUseUser {
  const context = useContext(UserContext);
  if (context === undefined) {
    throw new Error('useUser must be used within a UserProvider');
  }
  return context;
}

export { UserProvider, useUser };

Upvotes: 3

Views: 3009

Answers (1)

Subrato Pattanaik
Subrato Pattanaik

Reputation: 6059

The simple solution to make keys of IUseUser optional.

export interface IUseUser {
  userState?: IUserContext;
  dispatchUserContext?: Dispatch;
}

But why it is saying as empty {}? The answer is that you are creating a context with an empty object value. So, your default value is an empty object. You need to give default values to that context. Then you don't need to give optional keys.

const UserContext = createContext<IUseUser>({
  userState: {
    coverImg: '',
    profileImg: '',
    isDogSitter: false,
    isAvailable: false,
    phone: '',
    city: '',
    description: '',
    startDate: '',
    endDate: '',
    priceRate: '',
  },
  dispatchUserContext: (action: Action) => {},
});

Don't pass an empty object as a default value to your context. You can either pass undefined or value.

According to the official documentation of react,

"The defaultValue argument is only used when a component does not have a matching Provider above it in the tree. This can be helpful for testing components in isolation without wrapping them. Note: passing undefined as a Provider value does not cause consuming components to use defaultValue."

If you want to give undefined value to your context then in typescript you can create a context like this,

const UserContext = createContext<IUseUser | undefined>(undefined);

Upvotes: 3

Related Questions