Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
refactor!: rename and clean up utility types
  • Loading branch information
mrazauskas committed Feb 19, 2022
commit e19cfab6f77fd4e6b72c18c0711d7ef9b2e0b9bf
11 changes: 11 additions & 0 deletions packages/jest-mock/__typetests__/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"noUnusedLocals": false,
"noUnusedParameters": false,
"skipLibCheck": true,

"types": []
},
"include": ["./**/*"]
}
51 changes: 51 additions & 0 deletions packages/jest-mock/__typetests__/utility-types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {expectType} from 'tsd-lite';
import type {MethodKeys, PropertyKeys} from 'jest-mock';

interface SomeObject {
methodA(): void;
methodB(a: string): number;
propertyA: number;
propertyB: string;
}

declare const objectMethods: MethodKeys<SomeObject>;
declare const objectProperties: PropertyKeys<SomeObject>;

expectType<'methodA' | 'methodB'>(objectMethods);
expectType<'propertyA' | 'propertyB'>(objectProperties);

class SomeClass {
propertyB = 123;
private _propertyC: undefined;
#propertyD = 'abc';

constructor(public propertyA: string) {}

methodA(): void {
return;
}

methodB(b: string): string {
return b;
}

get propertyC() {
return this._propertyC;
}
set propertyC(value) {
this._propertyC = value;
}
}

declare const classMethods: MethodKeys<SomeClass>;
declare const classProperties: PropertyKeys<SomeClass>;

expectType<'methodA' | 'methodB'>(classMethods);
expectType<'propertyA' | 'propertyB' | 'propertyC'>(classProperties);
12 changes: 8 additions & 4 deletions packages/jest-mock/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
"engines": {
"node": "^12.13.0 || ^14.15.0 || ^16.13.0 || >=17.0.0"
},
"dependencies": {
"@jest/types": "^28.0.0-alpha.3",
"@types/node": "*"
},
"license": "MIT",
"main": "./build/index.js",
"types": "./build/index.d.ts",
Expand All @@ -23,6 +19,14 @@
},
"./package.json": "./package.json"
},
"dependencies": {
"@jest/types": "^28.0.0-alpha.3",
"@types/node": "*"
},
"devDependencies": {
"@tsd/typescript": "~4.5.5",
"tsd-lite": "^0.5.1"
},
"publishConfig": {
"access": "public"
}
Expand Down
120 changes: 56 additions & 64 deletions packages/jest-mock/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,87 +20,91 @@ export type MockFunctionMetadataType =
export type MockFunctionMetadata<
T,
Y extends Array<unknown>,
Type = MockFunctionMetadataType,
MetadataType = MockFunctionMetadataType,
> = {
ref?: number;
members?: Record<string, MockFunctionMetadata<T, Y>>;
mockImpl?: (...args: Y) => T;
name?: string;
refID?: number;
type?: Type;
type?: MetadataType;
value?: T;
length?: number;
};

export type MockableFunction = (...args: Array<any>) => any;
export type MethodKeysOf<T> = {
[K in keyof T]: T[K] extends MockableFunction ? K : never;
}[keyof T];
export type PropertyKeysOf<T> = {
[K in keyof T]: T[K] extends MockableFunction ? never : K;
export type ClassLike = {new (...args: Array<any>): any};

export type FunctionLike = (...args: Array<any>) => any;

export type MethodKeys<T> = {
[K in keyof T]: T[K] extends FunctionLike ? K : never;
}[keyof T];

export type ArgumentsOf<T> = T extends (...args: infer A) => any ? A : never;
export type PropertyKeys<T> = {
[K in keyof T]: T[K] extends FunctionLike ? never : K;
}[keyof T];

export type ConstructorArgumentsOf<T> = T extends new (...args: infer A) => any
? A
// TODO Replace this with TS ConstructorParameters utility type
// https://www.typescriptlang.org/docs/handbook/utility-types.html#constructorparameterstype
export type ConstructorParameters<T> = T extends new (...args: infer P) => any
? P
: never;

export type MaybeMockedConstructor<T> = T extends new (
...args: Array<any>
) => infer R
? MockInstance<R, ConstructorArgumentsOf<T>>
? MockInstance<R, ConstructorParameters<T>>
: T;
export type MockedFunction<T extends MockableFunction> = MockWithArgs<T> & {

export interface MockWithArgs<T extends FunctionLike>
extends MockInstance<ReturnType<T>, Parameters<T>> {
new (...args: ConstructorParameters<T>): T;
(...args: Parameters<T>): ReturnType<T>;
}

export type MockedFunction<T extends FunctionLike> = MockWithArgs<T> & {
[K in keyof T]: T[K];
};
export type MockedFunctionDeep<T extends MockableFunction> = MockWithArgs<T> &

export type MockedFunctionDeep<T extends FunctionLike> = MockWithArgs<T> &
MockedObjectDeep<T>;

export type MockedObject<T> = MaybeMockedConstructor<T> & {
[K in MethodKeysOf<T>]: T[K] extends MockableFunction
? MockedFunction<T[K]>
: T[K];
} & {[K in PropertyKeysOf<T>]: T[K]};
[K in MethodKeys<T>]: T[K] extends FunctionLike ? MockedFunction<T[K]> : T[K];
} & {[K in PropertyKeys<T>]: T[K]};

export type MockedObjectDeep<T> = MaybeMockedConstructor<T> & {
[K in MethodKeysOf<T>]: T[K] extends MockableFunction
[K in MethodKeys<T>]: T[K] extends FunctionLike
? MockedFunctionDeep<T[K]>
: T[K];
} & {[K in PropertyKeysOf<T>]: MaybeMockedDeep<T[K]>};
} & {[K in PropertyKeys<T>]: MaybeMockedDeep<T[K]>};

export type MaybeMockedDeep<T> = T extends MockableFunction
? MockedFunctionDeep<T>
export type MaybeMocked<T> = T extends FunctionLike
? MockedFunction<T>
: T extends object
? MockedObjectDeep<T>
? MockedObject<T>
: T;

export type MaybeMocked<T> = T extends MockableFunction
? MockedFunction<T>
export type MaybeMockedDeep<T> = T extends FunctionLike
? MockedFunctionDeep<T>
: T extends object
? MockedObject<T>
? MockedObjectDeep<T>
: T;

export type ArgsType<T> = T extends (...args: infer A) => any ? A : never;
export type Mocked<T> = {
[P in keyof T]: T[P] extends (...args: Array<any>) => any
? MockInstance<ReturnType<T[P]>, ArgsType<T[P]>>
: T[P] extends Constructable
[P in keyof T]: T[P] extends FunctionLike
? MockInstance<ReturnType<T[P]>, Parameters<T[P]>>
: T[P] extends ClassLike
? MockedClass<T[P]>
: T[P];
} & T;
export type MockedClass<T extends Constructable> = MockInstance<

export type MockedClass<T extends ClassLike> = MockInstance<
InstanceType<T>,
T extends new (...args: infer P) => any ? P : never
> & {
prototype: T extends {prototype: any} ? Mocked<T['prototype']> : never;
} & T;
export interface Constructable {
new (...args: Array<any>): any;
}

export interface MockWithArgs<T extends MockableFunction>
extends MockInstance<ReturnType<T>, ArgumentsOf<T>> {
new (...args: ConstructorArgumentsOf<T>): T;
(...args: ArgumentsOf<T>): ReturnType<T>;
}

export interface Mock<T, Y extends Array<unknown> = Array<unknown>>
extends Function,
Expand All @@ -109,9 +113,6 @@ export interface Mock<T, Y extends Array<unknown> = Array<unknown>>
(...args: Y): T;
}

export interface SpyInstance<T, Y extends Array<unknown>>
extends MockInstance<T, Y> {}

export interface MockInstance<T, Y extends Array<unknown>> {
_isMockFunction: true;
_protoImpl: Function;
Expand All @@ -129,13 +130,14 @@ export interface MockInstance<T, Y extends Array<unknown>> {
mockReturnThis(): this;
mockReturnValue(value: T): this;
mockReturnValueOnce(value: T): this;
mockResolvedValue(value: Unpromisify<T>): this;
mockResolvedValueOnce(value: Unpromisify<T>): this;
mockResolvedValue(value: Awaited<T>): this;
mockResolvedValueOnce(value: Awaited<T>): this;
mockRejectedValue(value: unknown): this;
mockRejectedValueOnce(value: unknown): this;
}

type Unpromisify<T> = T extends Promise<infer R> ? R : never;
export interface SpyInstance<T, Y extends Array<unknown>>
extends MockInstance<T, Y> {}

/**
* Possible types of a MockFunctionResult.
Expand Down Expand Up @@ -183,16 +185,6 @@ type MockFunctionConfig = {
specificMockImpls: Array<Function>;
};

// see https://github.com/Microsoft/TypeScript/issues/25215
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends (...args: Array<any>) => any ? never : K;
}[keyof T] &
string;
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends (...args: Array<any>) => any ? K : never;
}[keyof T] &
string;

const MOCK_CONSTRUCTOR_NAME = 'mockConstructor';

const FUNCTION_NAME_RESERVED_PATTERN = /[\s!-\/:-@\[-`{-~]/;
Expand Down Expand Up @@ -730,7 +722,7 @@ export class ModuleMocker {
// next function call will return this value or default return value
f.mockImplementationOnce(() => value);

f.mockResolvedValueOnce = (value: Unpromisify<T>) =>
f.mockResolvedValueOnce = (value: Awaited<T>) =>
f.mockImplementationOnce(() => Promise.resolve(value as T));

f.mockRejectedValueOnce = (value: unknown) =>
Expand All @@ -740,7 +732,7 @@ export class ModuleMocker {
// next function call will return specified return value or this one
f.mockImplementation(() => value);

f.mockResolvedValue = (value: Unpromisify<T>) =>
f.mockResolvedValue = (value: Awaited<T>) =>
f.mockImplementation(() => Promise.resolve(value as T));

f.mockRejectedValue = (value: unknown) =>
Expand Down Expand Up @@ -1003,27 +995,27 @@ export class ModuleMocker {
return fn;
}

spyOn<T extends {}, M extends NonFunctionPropertyNames<T>>(
spyOn<T, M extends PropertyKeys<T>>(
object: T,
methodName: M,
accessType: 'get',
): SpyInstance<T[M], []>;

spyOn<T extends {}, M extends NonFunctionPropertyNames<T>>(
spyOn<T, M extends PropertyKeys<T>>(
object: T,
methodName: M,
accessType: 'set',
): SpyInstance<void, [T[M]]>;

spyOn<T extends {}, M extends FunctionPropertyNames<T>>(
spyOn<T, M extends MethodKeys<T>>(
object: T,
methodName: M,
): T[M] extends (...args: Array<any>) => any
): T[M] extends FunctionLike
? SpyInstance<ReturnType<T[M]>, Parameters<T[M]>>
: never;

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
spyOn<T extends {}, M extends NonFunctionPropertyNames<T>>(
spyOn<T, M extends PropertyKeys<T>>(
object: T,
methodName: M,
accessType?: 'get' | 'set',
Expand Down Expand Up @@ -1094,7 +1086,7 @@ export class ModuleMocker {
return object[methodName];
}

private _spyOnProperty<T extends {}, M extends NonFunctionPropertyNames<T>>(
private _spyOnProperty<T, M extends PropertyKeys<T>>(
obj: T,
propertyName: M,
accessType: 'get' | 'set' = 'get',
Expand Down
2 changes: 2 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13210,7 +13210,9 @@ __metadata:
resolution: "jest-mock@workspace:packages/jest-mock"
dependencies:
"@jest/types": ^28.0.0-alpha.3
"@tsd/typescript": ~4.5.5
"@types/node": "*"
tsd-lite: ^0.5.1
languageName: unknown
linkType: soft

Expand Down