Repository: facebook/jest
File: packages/expect/src/types.ts (TypeScript)

Code before:
export type Expect = {
  <T = unknown>(actual: T): Matchers<void, T> &
    Inverse<Matchers<void, T>> &
    PromiseMatchers<T>;
} & BaseExpect &
  AsymmetricMatchers &
  Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>;

type Inverse<Matchers> = {
  /**
   * Inverse next matcher. If you know how to test something, `.not` lets you test its opposite.
   */
  not: Matchers;
};

export interface AsymmetricMatchers {
  any(sample: unknown): AsymmetricMatcher;
  anything(): AsymmetricMatcher;
  arrayContaining(sample: Array<unknown>): AsymmetricMatcher;
  closeTo(sample: number, precision?: number): AsymmetricMatcher;
  objectContaining(sample: Record<string, unknown>): AsymmetricMatcher;
  stringContaining(sample: string): AsymmetricMatcher;
  stringMatching(sample: string | RegExp): AsymmetricMatcher;
}

// if T is a function, return its parameters array type, otherwise return an unknown array type
type ConditionalFunctionParameters<T> = T extends (
  ...args: Array<unknown>
) => unknown
  ? Parameters<T>
  : Array<unknown>;

type PromiseMatchers<T = unknown> = {
  /**
   * Unwraps the reason of a rejected promise so any other matcher can be chained.
   * If the promise is fulfilled the assertion fails.
   */
  rejects: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>, T>>;
  /**
   * Unwraps the value of a fulfilled promise so any other matcher can be chained.
   * If the promise is rejected the assertion fails.
   */
  resolves: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>, T>>;
};

export interface Matchers<R extends void | Promise<void>, T = unknown> {
  /**
   * Ensures the last call to a mock function was provided specific args.
   */
  lastCalledWith(...expected: ConditionalFunctionParameters<T>): R;
  /**

Review comment (suggestion):
Hm.. In this use case, can it be not a function? I mean, isn’t it that `toHaveBeenCalledWith` should be used with functions. Or?

I just look at `toMatchSnapshot` again thinking that constraining types for the matcher would make sense here too. Do I miss something?

https://github.com/facebook/jest/blob/e703e6ed1861595d56e25a764642da5a32b32c5a/packages/jest-snapshot/src/types.ts#L38-L39

Code after:
export type Expect = {
  <T = unknown>(actual: T): Matchers<void, T> &
    Inverse<Matchers<void, T>> &
    PromiseMatchers<T>;
} & BaseExpect &
  AsymmetricMatchers &
  Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>;

type Inverse<Matchers> = {
  /**
   * Inverse next matcher. If you know how to test something, `.not` lets you test its opposite.
   */
  not: Matchers;
};

export interface AsymmetricMatchers {
  any(sample: unknown): AsymmetricMatcher;
  anything(): AsymmetricMatcher;
  arrayContaining(sample: Array<unknown>): AsymmetricMatcher;
  closeTo(sample: number, precision?: number): AsymmetricMatcher;
  objectContaining(sample: Record<string, unknown>): AsymmetricMatcher;
  stringContaining(sample: string): AsymmetricMatcher;
  stringMatching(sample: string | RegExp): AsymmetricMatcher;
}

type PromiseMatchers<T = unknown> = {
  /**
   * Unwraps the reason of a rejected promise so any other matcher can be chained.
   * If the promise is fulfilled the assertion fails.
   */
  rejects: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>, T>>;
  /**
   * Unwraps the value of a fulfilled promise so any other matcher can be chained.
   * If the promise is rejected the assertion fails.
   */
  resolves: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>, T>>;
};

type EnsureFunctionLike<T> = T extends (...args: any) => any ? T : never;

export interface Matchers<R extends void | Promise<void>, T = unknown> {
  /**
   * Ensures the last call to a mock function was provided specific args.
   */
  lastCalledWith(...expected: Parameters<EnsureFunctionLike<T>>): R;
  /**
   * Ensure that the last call to a mock function has returned a specified value.
   */
  lastReturnedWith(expected: unknown): R;
  /**
   * Ensure that a mock function is called with specific arguments on an Nth call.