1

I am trying to implement Typescript and Context API together in an application. I am facing the issue of implementing the function of deleteMovie and addMovie into the MovieContext.Provider's value prop.

Here's the error that I'm receiving:

Type '{ movies: MovieAttribute[]; deleteMovie: (id: number) => void; addMovie: (id: number, title: string) => void; }' is not assignable to type '{ movies: { id: number; title: string; }[]; }'.
  Object literal may only specify known properties, and 'deleteMovie' does not exist in type '{ movies: { id: number; title: string; }[]; }'.ts(2322)
index.d.ts(337, 9): The expected type comes from property 'value' which is declared here on type 'IntrinsicAttributes & ProviderProps<{ movies: { id: number; title: string; }[]; }>'

From what I understand from the error, am I correct to say that I have yet to declare that my Provider's value did not include a 'function type'. If so, how can I amend this issue?

MovieContext.tsx

import React, { createContext, useReducer } from 'react';
import MovieReducer from '../reducers/MovieReducer';

const initialState = { 
    movies: [
        {
            id: 1,
            title: "King Kong"
        },
        {
            id: 2,
            title: "Spiderman"
        }
    ]
};

export const MovieContext = createContext(initialState);

export const MovieProvider = (props: { children: React.ReactNode }) => {
    const [state, dispatch] = useReducer(MovieReducer, initialState);

    // Actions
    function deleteMovie(id: number): void {
        dispatch({
            type: 'DELETE_MOVIE',
            payload: { id, title: 'nil' }
        })
    }

    function addMovie(id: number, title: string): void {
        dispatch({
            type: 'ADD_MOVIE',
            payload: { id, title }
        })
    }

    return (
        <MovieContext.Provider value={{
            movies: state.movies,
            deleteMovie,
            addMovie
        }}>
            {props.children}
        </MovieContext.Provider>
    )
}

Do let me know if any part of the code can be improve as well! I just started working on Typescript recently and Context just literally today.

1 Answer 1

4

The type of the context is determined on it's declaration. You need to specify the type when calling createContext along with reasonable defaults if the context is retrieved without a context provider in the tree above:

// You could move the anonymous type between <> to an interface 
export const MovieContext = createContext<{
  movies: Movie[],
  deleteMovie(id: number): void;
  addMovie(id: number, title: string): void;
}>({
  ...initialState,
  addMovie: () => {},
  deleteMovie: () => {}
});

Playground Link

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. Can I clarify that addMovie: () => {} is declaring that addMovie is a function? If so, are there any other way to declare a function in typescript?
@MongChangHsi it's just an empty function, you could also use addMovie() {}. This empty function should never actually be invoked as the default value of the context is never used if you have a MovieContext.Provider as a parent. Alternate values for addMovies would be null! (forcing null in something that should not be null) or addMovie: () => { throw new Error("No context for movies exists")}. If you forget to add a provider both these would result in runtime errors (which is actually probably a good thing). The empty function above would just silently not do anything.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.