Home > Back-end >  Why jest.fn() can be assigned to any function in Typescript?
Why jest.fn() can be assigned to any function in Typescript?

Time:05-04

I'm confused how jest.fn() works in Typescript. For example

class MyClass {
  myFunction() {
    return 'hello'
  }
}

let myClass = new MyClass()
myClass.myFunction = jest.fn()

From my understanding, myClass.myFunction has a type of '() => string' but jest.fn() returns a 'Mock'. I notice that 'Mock' is in fact extends 'Function' but Function is less specific then () => string so how could this work?

CodePudding user response:

Looking at the types from @types/jest, it extends function but with a specific call signature:

interface Mock<T = any, Y extends any[] = any>
  extends Function, MockInstance<T, Y> {
    new (...args: Y): T;
    (...args: Y): T; // <--
}

fn() returns just Mock and because the default return type (T) is any, this is allowed.

fn can be called with type arguments to specify the return type explicitly or, more conveniently, the types can be inferred from the implementation function:

function fn<T, Y extends any[]>(implementation?: (...args: Y) => T): Mock<T, Y>;

Example:

// Identifies wrong return type (Type 'void' is not assignable to type 'string')
myClass.myFunction = jest.fn(() => { })

// Correct return type
myClass.myFunction = jest.fn(() => '')

Playground


If the types from the jest packages themselves are used, then jest.fn() without anything else will also yield an error, because it returns a Mock<UnknownFunction>.

Playground

  • Related