最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Typescript for React createContext and useContext - Stack Overflow

programmeradmin0浏览0评论

I have a React Context file with a stateful Provider to manage cookie preferences. It all works as expected but I'm having 1 issue with Typescript. My file looks like this:

import Cookies from 'js-cookie';
import React, { Component, ReactNode } from 'react';

interface Props {
  children: ReactNode | ReactNode[];
  functionalCookiesOn: boolean;
  performanceCookiesOn: boolean;
};

interface State {
  functionalCookiesOn: boolean;
  performanceCookiesOn: boolean;
};

// Initialise context storage
const CookiesContext = React.createContext({});
const { Consumer: CookiesConsumer } = CookiesContext;

class CookiesProvider extends Component<Props, State> {
  constructor(props: Props) {
    super(props);

    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.props;

    this.state = {
      functionalCookiesOn,
      performanceCookiesOn,
    };
  }

  ponentDidUpdate(_prevProps: Props, prevState: State) {
    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.state;

    // Set cookie to store functional cookies setting
    if (functionalCookiesOn !== prevState.functionalCookiesOn) {
      Cookies.set('functionalCookiesOn', functionalCookiesOn.toString());
    }

    // Set cookie to store performance cookies setting
    if (performanceCookiesOn !== prevState.performanceCookiesOn) {
      Cookies.set('performanceCookiesOn', performanceCookiesOn.toString());
    }
  }

  toggleAllCookies = () => {
    // Store reversed state for functional and performance cookies
    this.setState((prevState: State) => ({
      functionalCookiesOn: !prevState.functionalCookiesOn,
      performanceCookiesOn: !prevState.performanceCookiesOn,
    }));
  }

  render() {
    const { children } = this.props;

    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.state;

    const value = {
      functionalCookiesOn,
      performanceCookiesOn,
      toggleAllCookies: this.toggleAllCookies,
    };

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

export default CookiesContext;
export { CookiesConsumer, CookiesProvider };

When I use this in another function ponent it looks like this:

const AnotherComponent = () => {
  const {
    functionalCookiesOn,
    performanceCookiesOn,
    toggleAllCookies,
  } = useContext(CookiesContext);

  return (
    ...
  );
}

This throws errors such as:

Property 'functionalCookiesOn' does not exist on type '{}'.

This seems to me to do with the following line in the original file:

const CookiesContext = React.createContext({});

Because I initialise the context with an empty object (because at that stage it's got no values).

What's the correct way to initialise this or apply types to avoid this error?

I have a React Context file with a stateful Provider to manage cookie preferences. It all works as expected but I'm having 1 issue with Typescript. My file looks like this:

import Cookies from 'js-cookie';
import React, { Component, ReactNode } from 'react';

interface Props {
  children: ReactNode | ReactNode[];
  functionalCookiesOn: boolean;
  performanceCookiesOn: boolean;
};

interface State {
  functionalCookiesOn: boolean;
  performanceCookiesOn: boolean;
};

// Initialise context storage
const CookiesContext = React.createContext({});
const { Consumer: CookiesConsumer } = CookiesContext;

class CookiesProvider extends Component<Props, State> {
  constructor(props: Props) {
    super(props);

    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.props;

    this.state = {
      functionalCookiesOn,
      performanceCookiesOn,
    };
  }

  ponentDidUpdate(_prevProps: Props, prevState: State) {
    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.state;

    // Set cookie to store functional cookies setting
    if (functionalCookiesOn !== prevState.functionalCookiesOn) {
      Cookies.set('functionalCookiesOn', functionalCookiesOn.toString());
    }

    // Set cookie to store performance cookies setting
    if (performanceCookiesOn !== prevState.performanceCookiesOn) {
      Cookies.set('performanceCookiesOn', performanceCookiesOn.toString());
    }
  }

  toggleAllCookies = () => {
    // Store reversed state for functional and performance cookies
    this.setState((prevState: State) => ({
      functionalCookiesOn: !prevState.functionalCookiesOn,
      performanceCookiesOn: !prevState.performanceCookiesOn,
    }));
  }

  render() {
    const { children } = this.props;

    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.state;

    const value = {
      functionalCookiesOn,
      performanceCookiesOn,
      toggleAllCookies: this.toggleAllCookies,
    };

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

export default CookiesContext;
export { CookiesConsumer, CookiesProvider };

When I use this in another function ponent it looks like this:

const AnotherComponent = () => {
  const {
    functionalCookiesOn,
    performanceCookiesOn,
    toggleAllCookies,
  } = useContext(CookiesContext);

  return (
    ...
  );
}

This throws errors such as:

Property 'functionalCookiesOn' does not exist on type '{}'.

This seems to me to do with the following line in the original file:

const CookiesContext = React.createContext({});

Because I initialise the context with an empty object (because at that stage it's got no values).

What's the correct way to initialise this or apply types to avoid this error?

Share Improve this question asked Jun 7, 2019 at 14:50 CaribouCodeCaribouCode 14.4k33 gold badges111 silver badges185 bronze badges 1
  • Yes, you need to provide initial values. Otherwise typescript will throw the error – Yash Gadle Commented Jun 7, 2019 at 15:00
Add a ment  | 

2 Answers 2

Reset to default 7

I think you can provide a type to your call to createContext

const CookiesContext = React.createContext<Partial<Props>>({});

<Partial> allows you to create the context without default values.

Try this out;-

import Cookies from 'js-cookie';
import React, { Component, ReactNode } from 'react';

interface Props {
  children: ReactNode | ReactNode[];
  functionalCookiesOn: boolean;
  performanceCookiesOn: boolean;
};

interface State {
  functionalCookiesOn: boolean;
  performanceCookiesOn: boolean;
};

// Initialise context storage
const CookiesContext = React.createContext({
    functionalCookiesOn: false,
    performanceCookiesOn: false,
    toggleAllCookies: () => null
});
const { Consumer: CookiesConsumer } = CookiesContext;

class CookiesProvider extends Component<Props, State> {
  constructor(props: Props) {
    super(props);

    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.props;

    this.state = {
      functionalCookiesOn,
      performanceCookiesOn,
    };
  }

  ponentDidUpdate(_prevProps: Props, prevState: State) {
    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.state;

    // Set cookie to store functional cookies setting
    if (functionalCookiesOn !== prevState.functionalCookiesOn) {
      Cookies.set('functionalCookiesOn', functionalCookiesOn.toString());
    }

    // Set cookie to store performance cookies setting
    if (performanceCookiesOn !== prevState.performanceCookiesOn) {
      Cookies.set('performanceCookiesOn', performanceCookiesOn.toString());
    }
  }

  toggleAllCookies = () => {
    // Store reversed state for functional and performance cookies
    this.setState((prevState: State) => ({
      functionalCookiesOn: !prevState.functionalCookiesOn,
      performanceCookiesOn: !prevState.performanceCookiesOn,
    }));
  }

  render() {
    const { children } = this.props;

    const {
      functionalCookiesOn,
      performanceCookiesOn,
    } = this.state;

    const value = {
      functionalCookiesOn,
      performanceCookiesOn,
      toggleAllCookies: this.toggleAllCookies,
    };

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

export default CookiesContext;
export { CookiesConsumer, CookiesProvider };

This should do the trick and typescript will start intellisense.

发布评论

评论列表(0)

  1. 暂无评论