Skip to content

Bound functions for find* queries throw error in typescript when waitForElementOptions argument is supplied. #291

Closed
@le0nik

Description

@le0nik
  • dom-testing-library version: 5.2.1
  • react-testing-library version: 8.0.1
  • react version: 16.8.6
  • node version: 10.16.0
  • npm (or yarn) version: npm(6.9.0), yarn(1.16.0)

Relevant code or config:

const { findByText } = render(<App />);
const button = await findByText( // TS error: "Expected 1-2 arguments, but got 3"
  /inc/i,
  {},
  {
    timeout: 100
  }
);

What you did:

Used bound findByText function returned by render from @testing-library/react with waitForElementOptions argument.

What happened:

Typescript threw an error Expected 1-2 arguments, but got 3

Reproduction:

https://codesandbox.io/s/uok74

Take a look at App.test.tsx.

Problem description:

waitForElementOptions argument is not considered for bound functions type here:

export type BoundFunction<T> = T extends (
attribute: string,
element: HTMLElement,
text: infer P,
options: infer Q,
) => infer R
? (text: P, options?: Q) => R
: T extends (a1: any, text: infer P, options: infer Q) => infer R
? (text: P, options?: Q) => R
: never

Suggested solution:

Another signature should be added that supports waitForElementOptions argument to the type linked above.

I tried to do that, but my attempt failed. Here's what I've tried:

export type BoundFunction<T> = T extends (
  attribute: string,
  element: HTMLElement,
  text: infer P,
  options: infer Q,
) => infer R
  ? (text: P, options?: Q) => R
  : T extends (a1: any, text: infer P, options: infer Q, waitForElementOptions: infer S) => infer R
  ? (text: P, options?: Q, waitForElementOptions?: S) => R
  : T extends (a1: any, text: infer P, options: infer Q) => infer R
  ? (text: P, options?: Q) => R
  : never

Note these 2 lines that I've added:

: T extends (a1: any, text: infer P, options: infer Q, waitForElementOptions: infer S) => infer R
? (text: P, options?: Q, waitForElementOptions?: S) => R

It fixed the case with bound find* queries, now they accept waitForElementOptions argument, but it breaks proper typechecking for get* and other bound queries, that accept fewer arguments. For some reason typescript uses this signature for them too, which results in ability to call them with more arguments than they accept.

Example:

const { getByText } = render(<App />);
const button = getByText( // TS should throw error here, but doesn't
  /inc/i,
  {},
  {
    timeout: 100
  }
);

I probably don't fully understand how assignability rules work for function signatures in conditional types in Typescript(I think it should be from top to bottom, from more to less specific signatures). Would be great if someone could find a solution to this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions