简体   繁体   中英

Infer TypeScript type from assignment after declaration

When writing tests for React components, it's typical to initialize a component wrapper (say wrapper ) in a beforeEach block and then use it in the subsequent tests. However, in order to do this, you have to declare wrapper before its assignment and give it an explicit type or else TypeScript will complain about the lack of a type. Unfortunately, this type can be quite complex to figure out / write out.

In the example below, is there any way to 'delay' TypeScript from complaining about the lack of a type for wrapper in the example below and get it to infer the type from the place where wrapper is assigned?

Alternatively, is there a better pattern to lay out variables which makes typing easier?

describe('suite', () => {
  // will trigger a no implicit any error
  // but it's quite complex to manually write out the type here
  let wrapper;

  beforeEach(() => {
    const SomeElement = complexFunctionWithGenericParams(someParam);

    // ideally, we want TS to infer the type of `wrapper` from this statement
    wrapper = mountComponent(<SomeElement />);
  })

  it('does something', () => {
    expect(wrapper.state.someField).toBe(5);
  }
}

There's no way to infer a type from assignment because it should be inferred at declaration time. The point of local variables in tests is that they can be used between blocks, this means that they can be assigned multiple times. Even if this kind of inference were possible, it would be ambiguous:

let foo; // is the type supposed to be a number, or a string, or both, or any?

it('...', () => {
  foo = 1;
});

it('...', () => {
  foo = 'foo';
});

So the type should be specified explicitly, eg with ReturnType :

let wrapper: ReturnType<typeof mount>;

mount is generic, return type may vary, ReturnType may be more complicated with generic functions .

Since Enzyme shallow and mount should be explicitly specified with generic parameters:

wrapper = mount<typeof SomeElement, ISomeElementProps>(<SomeElement />);

It's more straightforward to specify generic type directly, since it's known what type it is ( ReactWrapper ):

let wrapper: Enzyme.ReactWrapper<ISomeElementProps, ISomeElementState, typeof SomeElement>

Although not an entirely different pattern, the following has helped get rid of the said warnings in a similar situation.

import { shallow, mount, ReactWrapper } from 'enzyme'

describe('suite', () => {
  let wrapper: ReactWrapper;

  beforeEach(() => {
    ...
    wrapper = mount or shallow 
  })

  it('does something', () => {
    ...
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM