user7605119
user7605119

Reputation:

Property 'xxx' does not exist on type 'Readonly<{}>'

I'm trying to write tests for a React Typescript component. App.tsx:

import * as React from 'react';
import { Button } from 'react-bootstrap';

interface Igift {
  id: number;
}
interface IAppState {
  gifts: Igift[];
}
class App extends React.Component<{}, IAppState> {
  public state = {
    gifts: []
  };

  public addGift = () => {
    const { gifts } = this.state;
    const ids = this.state.gifts.map(ourGift => ourGift.id);

    const maxId = ids.length > 0 ? Math.max(...ids) : 0;

    gifts.push({ id: maxId + 1 });

    this.setState({ gifts });
  };

  public render() {
    return (
      <div>
        <h2>Gift Giver</h2>
        <Button className="btn-add" onClick={this.addGift}>
          Add Gift
        </Button>
      </div>
    );
  }
}

export default App;

and a test for that component. App.test.tsx:

import { shallow } from 'enzyme';
import * as React from 'react';

import App from './App';

const app = shallow(<App />);

describe('App', () => {
  it('renders correctly', () => {
    expect(app).toMatchSnapshot();
  });

  it('initializes the `state` with an empty list of gifts', () => {
    expect(app.state().gifts).toEqual([]);
  });

  it('adds a new gift to `state` when clicking the `add gift` button', () => {
    app.find('.btn-add').simulate('click');

    expect(app.state().gifts).toEqual([{ id: 1 }]);
  });
});

I'm getting a following error:

(14,24): Property 'gifts' does not exist on type 'Readonly<{}>'.

In App.test.tsx I cannot seem to find any details regarding that. The app is bootstrapped with create-react-app with ts version of the scripts. The tests pass but when I try starting the app, it throws that error. What need to be done?

Upvotes: 3

Views: 5780

Answers (1)

Oblosys
Oblosys

Reputation: 15106

Because <App/> has the generic type JSX.Element, it does not contain enough information to infer the state type in the result of shallow (the same holds for the props & component types). You can fix it by exporting IAppState from App.tsx and parameterizing shallow with the component, props, & state types:

import App, {IAppState} from './App';
..
const app = shallow<App, {}, IAppState>(<App />); // {} is props type
..

This should also correctly type app.instance() and app.setProps(). Alternatively, you could choose to just test in plain JavaScript, as I'm not sure doing this in TypeScript is worth the extra effort.

Upvotes: 3

Related Questions