UNPKG

expect-type

Version:

[![CI](https://github.com/mmkal/expect-type/actions/workflows/ci.yml/badge.svg)](https://github.com/mmkal/expect-type/actions/workflows/ci.yml) ![npm](https://img.shields.io/npm/dt/expect-type) [![X (formerly Twitter) Follow](https://img.shields.io/twitte

830 lines (829 loc) 33 kB
import type { StrictEqualUsingBranding } from './branding'; import type { ExpectAny, ExpectArray, ExpectBigInt, ExpectBoolean, ExpectFunction, ExpectNever, ExpectNull, ExpectNullable, ExpectNumber, ExpectObject, ExpectString, ExpectSymbol, ExpectUndefined, ExpectUnknown, ExpectVoid, MismatchInfo, Scolder } from './messages'; import type { ConstructorOverloadParameters, OverloadParameters, OverloadReturnTypes, OverloadsNarrowedByParameters } from './overloads'; import type { AValue, DeepPickMatchingProps, Extends, IsUnion, MismatchArgs, Not, StrictEqualUsingTSInternalIdenticalToOperator } from './utils'; export * from './branding'; export * from './messages'; export * from './overloads'; export * from './utils'; /** * Represents the positive assertion methods available for type checking in the * {@linkcode expectTypeOf()} utility. */ export interface PositiveExpectTypeOf<Actual> extends BaseExpectTypeOf<Actual, { positive: true; branded: false; }> { /** * Similar to jest's `expect(...).toMatchObject(...)` but for types. * Deeply "picks" the properties of the actual type based on the expected type, then performs a strict check to make sure the types match `Expected`. * * Note: optional properties on the expected type are not allowed to be missing on the actual type. */ toMatchObjectType: <Expected extends IsUnion<Expected> extends true ? 'toMatchObject does not support union types' : Not<Extends<Expected, Record<string, unknown>>> extends true ? 'toMatchObject only supports object types' : StrictEqualUsingTSInternalIdenticalToOperator<DeepPickMatchingProps<Actual, Expected>, Expected> extends true ? unknown : MismatchInfo<DeepPickMatchingProps<Actual, Expected>, Expected>>(...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<DeepPickMatchingProps<Actual, Expected>, Expected>, true>) => true; toExtend<Expected extends Extends<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(...MISMATCH: MismatchArgs<Extends<Actual, Expected>, true>): true; toEqualTypeOf: { /** * Uses TypeScript's internal technique to check for type "identicalness". * * It will check if the types are fully equal to each other. * It will not fail if two objects have different values, but the same type. * It will fail however if an object is missing a property. * * **_Unexpected failure_**? For a more permissive but less performant * check that accommodates for equivalent intersection types, * use {@linkcode branded | .branded.toEqualTypeOf()}. * @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing | The documentation for details}. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() * * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) * * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) * ``` * * @param value - The value to compare against the expected type. * @param MISMATCH - The mismatch arguments. * @returns `true`. */ <Expected extends StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(value: Expected & AValue, // reason for `& AValue`: make sure this is only the selected overload when the end-user passes a value for an inferred typearg. The `Mismatch` type does match `AValue`. ...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected>, true>): true; /** * Uses TypeScript's internal technique to check for type "identicalness". * * It will check if the types are fully equal to each other. * It will not fail if two objects have different values, but the same type. * It will fail however if an object is missing a property. * * **_Unexpected failure_**? For a more permissive but less performant * check that accommodates for equivalent intersection types, * use {@linkcode branded | .branded.toEqualTypeOf()}. * @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing | The documentation for details}. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() * * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) * * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) * ``` * * @param MISMATCH - The mismatch arguments. * @returns `true`. */ <Expected extends StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected>, true>): true; }; toExtend: <Expected extends Extends<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(...MISMATCH: MismatchArgs<Extends<Actual, Expected>, true>) => true; /** * @deprecated - use either `toMatchObjectType` or `toExtend` instead * - use `toMatchObjectType` to perform a strict check on a subset of your type's keys * - use `toExtend` to check if your type extends the expected type */ toMatchTypeOf: { /** * @deprecated - use either `toMatchObjectType` or `toExtend` instead * - use `toMatchObjectType` to perform a strict check on a subset of your type's keys * - use `toExtend` to check if your type extends the expected type * A less strict version of {@linkcode toEqualTypeOf | .toEqualTypeOf()} * that allows for extra properties. * This is roughly equivalent to an `extends` constraint * in a function type argument. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) * ``` * * @param value - The value to compare against the expected type. * @param MISMATCH - The mismatch arguments. * @returns `true`. */ <Expected extends Extends<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(value: Expected & AValue, // reason for `& AValue`: make sure this is only the selected overload when the end-user passes a value for an inferred typearg. The `Mismatch` type does match `AValue`. ...MISMATCH: MismatchArgs<Extends<Actual, Expected>, true>): true; /** * @deprecated - use either `toMatchObjectType` or `toExtend` instead * - use `toMatchObjectType` to perform a strict check on a subset of your type's keys * - use `toExtend` to check if your type extends the expected type * A less strict version of {@linkcode toEqualTypeOf | .toEqualTypeOf()} * that allows for extra properties. * This is roughly equivalent to an `extends` constraint * in a function type argument. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) * ``` * * @param MISMATCH - The mismatch arguments. * @returns `true`. */ <Expected extends Extends<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(...MISMATCH: MismatchArgs<Extends<Actual, Expected>, true>): true; }; /** * Checks whether an object has a given property. * * @example * <caption>check that properties exist</caption> * ```ts * const obj = { a: 1, b: '' } * * expectTypeOf(obj).toHaveProperty('a') * * expectTypeOf(obj).not.toHaveProperty('c') * ``` * * @param key - The property key to check for. * @param MISMATCH - The mismatch arguments. * @returns `true`. */ toHaveProperty: <KeyType extends keyof Actual>(key: KeyType, ...MISMATCH: MismatchArgs<Extends<KeyType, keyof Actual>, true>) => KeyType extends keyof Actual ? PositiveExpectTypeOf<Actual[KeyType]> : true; /** * Inverts the result of the following assertions. * * @example * ```ts * expectTypeOf({ a: 1 }).not.toMatchTypeOf({ b: 1 }) * ``` */ not: NegativeExpectTypeOf<Actual>; /** * Intersection types can cause issues with * {@linkcode toEqualTypeOf | .toEqualTypeOf()}: * ```ts * // ❌ The following line doesn't compile, even though the types are arguably the same. * expectTypeOf<{ a: 1 } & { b: 2 }>().toEqualTypeOf<{ a: 1; b: 2 }>() * ``` * This helper works around this problem by using * a more permissive but less performant check. * * __Note__: This comes at a performance cost, and can cause the compiler * to 'give up' if used with excessively deep types, so use sparingly. * * @see {@link https://github.com/mmkal/expect-type/pull/21 | Reference} */ branded: { /** * Uses TypeScript's internal technique to check for type "identicalness". * * It will check if the types are fully equal to each other. * It will not fail if two objects have different values, but the same type. * It will fail however if an object is missing a property. * * **_Unexpected failure_**? For a more permissive but less performant * check that accommodates for equivalent intersection types, * use {@linkcode PositiveExpectTypeOf.branded | .branded.toEqualTypeOf()}. * @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing | The documentation for details}. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() * * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) * * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) * ``` * * @param MISMATCH - The mismatch arguments. * @returns `true`. */ toEqualTypeOf: <Expected extends StrictEqualUsingBranding<Actual, Expected> extends true ? unknown : MismatchInfo<Actual, Expected>>(...MISMATCH: MismatchArgs<StrictEqualUsingBranding<Actual, Expected>, true>) => true; }; } /** * Represents the negative expectation type for the {@linkcode Actual} type. */ export interface NegativeExpectTypeOf<Actual> extends BaseExpectTypeOf<Actual, { positive: false; }> { /** * Similar to jest's `expect(...).toMatchObject(...)` but for types. * Deeply "picks" the properties of the actual type based on the expected type, then performs a strict check to make sure the types match `Expected`. * * @example * ```ts * expectTypeOf({a: 1, b: 2}).toMatchObjectType<{a: number}> // passes * expectTypeOf({a: 1, b: 2}).toMatchObjectType<{a: string}> // fails * ``` */ toMatchObjectType: <Expected>(...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Pick<Actual, keyof Actual & keyof Expected>, Expected>, false>) => true; toExtend<Expected>(...MISMATCH: MismatchArgs<Extends<Actual, Expected>, false>): true; toEqualTypeOf: { /** * Uses TypeScript's internal technique to check for type "identicalness". * * It will check if the types are fully equal to each other. * It will not fail if two objects have different values, but the same type. * It will fail however if an object is missing a property. * * **_Unexpected failure_**? For a more permissive but less performant * check that accommodates for equivalent intersection types, * use {@linkcode PositiveExpectTypeOf.branded | .branded.toEqualTypeOf()}. * @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing | The documentation for details}. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() * * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) * * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) * ``` * * @param value - The value to compare against the expected type. * @param MISMATCH - The mismatch arguments. * @returns `true`. */ <Expected>(value: Expected & AValue, ...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected>, false>): true; /** * Uses TypeScript's internal technique to check for type "identicalness". * * It will check if the types are fully equal to each other. * It will not fail if two objects have different values, but the same type. * It will fail however if an object is missing a property. * * **_Unexpected failure_**? For a more permissive but less performant * check that accommodates for equivalent intersection types, * use {@linkcode PositiveExpectTypeOf.branded | .branded.toEqualTypeOf()}. * @see {@link https://github.com/mmkal/expect-type#why-is-my-assertion-failing | The documentation for details}. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() * * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) * * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) * ``` * * @param MISMATCH - The mismatch arguments. * @returns `true`. */ <Expected>(...MISMATCH: MismatchArgs<StrictEqualUsingTSInternalIdenticalToOperator<Actual, Expected>, false>): true; }; toMatchTypeOf: { /** * A less strict version of * {@linkcode PositiveExpectTypeOf.toEqualTypeOf | .toEqualTypeOf()} * that allows for extra properties. * This is roughly equivalent to an `extends` constraint * in a function type argument. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) * ``` * * @param value - The value to compare against the expected type. * @param MISMATCH - The mismatch arguments. * @returns `true`. */ <Expected>(value: Expected & AValue, // reason for `& AValue`: make sure this is only the selected overload when the end-user passes a value for an inferred typearg. The `Mismatch` type does match `AValue`. ...MISMATCH: MismatchArgs<Extends<Actual, Expected>, false>): true; /** * A less strict version of * {@linkcode PositiveExpectTypeOf.toEqualTypeOf | .toEqualTypeOf()} * that allows for extra properties. * This is roughly equivalent to an `extends` constraint * in a function type argument. * * @example * <caption>Using generic type argument syntax</caption> * ```ts * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() * ``` * * @example * <caption>Using inferred type syntax by passing a value</caption> * ```ts * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) * ``` * * @param MISMATCH - The mismatch arguments. * @returns `true`. */ <Expected>(...MISMATCH: MismatchArgs<Extends<Actual, Expected>, false>): true; }; /** * Checks whether an object has a given property. * * @example * <caption>check that properties exist</caption> * ```ts * const obj = { a: 1, b: '' } * * expectTypeOf(obj).toHaveProperty('a') * * expectTypeOf(obj).not.toHaveProperty('c') * ``` * * @param key - The property key to check for. * @param MISMATCH - The mismatch arguments. * @returns `true`. */ toHaveProperty: <KeyType extends string | number | symbol>(key: KeyType, ...MISMATCH: MismatchArgs<Extends<KeyType, keyof Actual>, false>) => true; } /** * Represents a conditional type that selects either * {@linkcode PositiveExpectTypeOf} or {@linkcode NegativeExpectTypeOf} based * on the value of the `positive` property in the {@linkcode Options} type. */ export type ExpectTypeOf<Actual, Options extends { positive: boolean; }> = Options['positive'] extends true ? PositiveExpectTypeOf<Actual> : NegativeExpectTypeOf<Actual>; /** * Represents the base interface for the * {@linkcode expectTypeOf()} function. * Provides a set of assertion methods to perform type checks on a value. */ export interface BaseExpectTypeOf<Actual, Options extends { positive: boolean; }> { /** * Checks whether the type of the value is `any`. */ toBeAny: Scolder<ExpectAny<Actual>, Options>; /** * Checks whether the type of the value is `unknown`. */ toBeUnknown: Scolder<ExpectUnknown<Actual>, Options>; /** * Checks whether the type of the value is `never`. */ toBeNever: Scolder<ExpectNever<Actual>, Options>; /** * Checks whether the type of the value is `function`. */ toBeFunction: Scolder<ExpectFunction<Actual>, Options>; /** * Checks whether the type of the value is `object`. */ toBeObject: Scolder<ExpectObject<Actual>, Options>; /** * Checks whether the type of the value is an {@linkcode Array}. */ toBeArray: Scolder<ExpectArray<Actual>, Options>; /** * Checks whether the type of the value is `number`. */ toBeNumber: Scolder<ExpectNumber<Actual>, Options>; /** * Checks whether the type of the value is `string`. */ toBeString: Scolder<ExpectString<Actual>, Options>; /** * Checks whether the type of the value is `boolean`. */ toBeBoolean: Scolder<ExpectBoolean<Actual>, Options>; /** * Checks whether the type of the value is `void`. */ toBeVoid: Scolder<ExpectVoid<Actual>, Options>; /** * Checks whether the type of the value is `symbol`. */ toBeSymbol: Scolder<ExpectSymbol<Actual>, Options>; /** * Checks whether the type of the value is `null`. */ toBeNull: Scolder<ExpectNull<Actual>, Options>; /** * Checks whether the type of the value is `undefined`. */ toBeUndefined: Scolder<ExpectUndefined<Actual>, Options>; /** * Checks whether the type of the value is `null` or `undefined`. */ toBeNullable: Scolder<ExpectNullable<Actual>, Options>; /** * Transform that type of the value via a callback. * * @param fn - A callback that transforms the input value. Note that this function is not actually called - it's only used for type inference. * @returns A new type which can be used for further assertions. */ map: <T>(fn: (value: Actual) => T) => ExpectTypeOf<T, Options>; /** * Checks whether the type of the value is **`bigint`**. * * @example * <caption>#### Distinguish between **`number`** and **`bigint`**</caption> * * ```ts * import { expectTypeOf } from 'expect-type' * * const aVeryBigInteger = 10n ** 100n * * expectTypeOf(aVeryBigInteger).not.toBeNumber() * * expectTypeOf(aVeryBigInteger).toBeBigInt() * ``` * * @since 1.1.0 */ toBeBigInt: Scolder<ExpectBigInt<Actual>, Options>; /** * Checks whether a function is callable with the given parameters. * * __Note__: You cannot negate this assertion with * {@linkcode PositiveExpectTypeOf.not | .not}, you need to use * `ts-expect-error` instead. * * @example * ```ts * const f = (a: number) => [a, a] * * expectTypeOf(f).toBeCallableWith(1) * ``` * * __Known Limitation__: This assertion will likely fail if you try to use it * with a generic function or an overload. * @see {@link https://github.com/mmkal/expect-type/issues/50 | This issue} for an example and a workaround. * * @param args - The arguments to check for callability. * @returns `true`. */ toBeCallableWith: Options['positive'] extends true ? <Args extends OverloadParameters<Actual>>(...args: Args) => ExpectTypeOf<OverloadsNarrowedByParameters<Actual, Args>, Options> : never; /** * Checks whether a class is constructible with the given parameters. * * @example * ```ts * expectTypeOf(Date).toBeConstructibleWith('1970') * * expectTypeOf(Date).toBeConstructibleWith(0) * * expectTypeOf(Date).toBeConstructibleWith(new Date()) * * expectTypeOf(Date).toBeConstructibleWith() * ``` * * @param args - The arguments to check for constructibility. * @returns `true`. */ toBeConstructibleWith: Options['positive'] extends true ? <Args extends ConstructorOverloadParameters<Actual>>(...args: Args) => true : never; /** * Equivalent to the {@linkcode Extract} utility type. * Helps narrow down complex union types. * * @example * ```ts * type ResponsiveProp<T> = T | T[] | { xs?: T; sm?: T; md?: T } * * interface CSSProperties { * margin?: string * padding?: string * } * * function getResponsiveProp<T>(_props: T): ResponsiveProp<T> { * return {} * } * * const cssProperties: CSSProperties = { margin: '1px', padding: '2px' } * * expectTypeOf(getResponsiveProp(cssProperties)) * .extract<{ xs?: any }>() // extracts the last type from a union * .toEqualTypeOf<{ * xs?: CSSProperties * sm?: CSSProperties * md?: CSSProperties * }>() * * expectTypeOf(getResponsiveProp(cssProperties)) * .extract<unknown[]>() // extracts an array from a union * .toEqualTypeOf<CSSProperties[]>() * ``` * * __Note__: If no type is found in the union, it will return `never`. * * @param v - The type to extract from the union. * @returns The type after extracting the type from the union. */ extract: <V>(v?: V) => ExpectTypeOf<Extract<Actual, V>, Options>; /** * Equivalent to the {@linkcode Exclude} utility type. * Removes types from a union. * * @example * ```ts * type ResponsiveProp<T> = T | T[] | { xs?: T; sm?: T; md?: T } * * interface CSSProperties { * margin?: string * padding?: string * } * * function getResponsiveProp<T>(_props: T): ResponsiveProp<T> { * return {} * } * * const cssProperties: CSSProperties = { margin: '1px', padding: '2px' } * * expectTypeOf(getResponsiveProp(cssProperties)) * .exclude<unknown[]>() * .exclude<{ xs?: unknown }>() // or just `.exclude<unknown[] | { xs?: unknown }>()` * .toEqualTypeOf<CSSProperties>() * ``` */ exclude: <V>(v?: V) => ExpectTypeOf<Exclude<Actual, V>, Options>; /** * Equivalent to the {@linkcode Pick} utility type. * Helps select a subset of properties from an object type. * * @example * ```ts * interface Person { * name: string * age: number * } * * expectTypeOf<Person>() * .pick<'name'>() * .toEqualTypeOf<{ name: string }>() * ``` * * @param keyToPick - The property key to pick. * @returns The type after picking the property. */ pick: <KeyToPick extends keyof Actual>(keyToPick?: KeyToPick) => ExpectTypeOf<Pick<Actual, KeyToPick>, Options>; /** * Equivalent to the {@linkcode Omit} utility type. * Helps remove a subset of properties from an object type. * * @example * ```ts * interface Person { * name: string * age: number * } * * expectTypeOf<Person>().omit<'name'>().toEqualTypeOf<{ age: number }>() * ``` * * @param keyToOmit - The property key to omit. * @returns The type after omitting the property. */ omit: <KeyToOmit extends keyof Actual | (PropertyKey & Record<never, never>)>(keyToOmit?: KeyToOmit) => ExpectTypeOf<Omit<Actual, KeyToOmit>, Options>; /** * Extracts a certain function argument with `.parameter(number)` call to * perform other assertions on it. * * @example * ```ts * function foo(a: number, b: string) { * return [a, b] * } * * expectTypeOf(foo).parameter(0).toBeNumber() * * expectTypeOf(foo).parameter(1).toBeString() * ``` * * @param index - The index of the parameter to extract. * @returns The extracted parameter type. */ parameter: <Index extends number>(index: Index) => ExpectTypeOf<OverloadParameters<Actual>[Index], Options>; /** * Equivalent to the {@linkcode Parameters} utility type. * Extracts function parameters to perform assertions on its value. * Parameters are returned as an array. * * @example * ```ts * function noParam() {} * * function hasParam(s: string) {} * * expectTypeOf(noParam).parameters.toEqualTypeOf<[]>() * * expectTypeOf(hasParam).parameters.toEqualTypeOf<[string]>() * ``` */ parameters: ExpectTypeOf<OverloadParameters<Actual>, Options>; /** * Equivalent to the {@linkcode ConstructorParameters} utility type. * Extracts constructor parameters as an array of values and * perform assertions on them with this method. * * For overloaded constructors it will return a union of all possible parameter-tuples. * * @example * ```ts * expectTypeOf(Date).constructorParameters.toEqualTypeOf< * [] | [string | number | Date] * >() * ``` */ constructorParameters: ExpectTypeOf<ConstructorOverloadParameters<Actual>, Options>; /** * Equivalent to the {@linkcode ThisParameterType} utility type. * Extracts the `this` parameter of a function to * perform assertions on its value. * * @example * ```ts * function greet(this: { name: string }, message: string) { * return `Hello ${this.name}, here's your message: ${message}` * } * * expectTypeOf(greet).thisParameter.toEqualTypeOf<{ name: string }>() * ``` */ thisParameter: ExpectTypeOf<ThisParameterType<Actual>, Options>; /** * Equivalent to the {@linkcode InstanceType} utility type. * Extracts the instance type of a class to perform assertions on. * * @example * ```ts * expectTypeOf(Date).instance.toHaveProperty('toISOString') * ``` */ instance: Actual extends new (...args: any[]) => infer I ? ExpectTypeOf<I, Options> : never; /** * Equivalent to the {@linkcode ReturnType} utility type. * Extracts the return type of a function. * * @example * ```ts * expectTypeOf(() => {}).returns.toBeVoid() * * expectTypeOf((a: number) => [a, a]).returns.toEqualTypeOf([1, 2]) * ``` */ returns: Actual extends Function ? ExpectTypeOf<OverloadReturnTypes<Actual>, Options> : never; /** * Extracts resolved value of a Promise, * so you can perform other assertions on it. * * @example * ```ts * async function asyncFunc() { * return 123 * } * * expectTypeOf(asyncFunc).returns.resolves.toBeNumber() * * expectTypeOf(Promise.resolve('string')).resolves.toBeString() * ``` * * Type Equivalent: * ```ts * type Resolves<PromiseType> = PromiseType extends PromiseLike<infer ResolvedType> * ? ResolvedType * : never * ``` */ resolves: Actual extends PromiseLike<infer ResolvedType> ? ExpectTypeOf<ResolvedType, Options> : never; /** * Extracts array item type to perform assertions on. * * @example * ```ts * expectTypeOf([1, 2, 3]).items.toEqualTypeOf<number>() * * expectTypeOf([1, 2, 3]).items.not.toEqualTypeOf<string>() * ``` * * __Type Equivalent__: * ```ts * type Items<ArrayType> = ArrayType extends ArrayLike<infer ItemType> * ? ItemType * : never * ``` */ items: Actual extends ArrayLike<infer ItemType> ? ExpectTypeOf<ItemType, Options> : never; /** * Extracts the type guarded by a function to perform assertions on. * * @example * ```ts * function isString(v: any): v is string { * return typeof v === 'string' * } * * expectTypeOf(isString).guards.toBeString() * ``` */ guards: Actual extends (v: any, ...args: any[]) => v is infer T ? ExpectTypeOf<T, Options> : never; /** * Extracts the type asserted by a function to perform assertions on. * * @example * ```ts * function assertNumber(v: any): asserts v is number { * if (typeof v !== 'number') * throw new TypeError('Nope !') * } * * expectTypeOf(assertNumber).asserts.toBeNumber() * ``` */ asserts: Actual extends (v: any, ...args: any[]) => asserts v is infer T ? unknown extends T ? never : ExpectTypeOf<T, Options> : never; } /** * Represents a function that allows asserting the expected type of a value. */ export type _ExpectTypeOf = { /** * Asserts the expected type of a value. * * @param actual - The actual value being asserted. * @returns An object representing the expected type assertion. */ <Actual>(actual: Actual): ExpectTypeOf<Actual, { positive: true; branded: false; }>; /** * Asserts the expected type of a value without providing an actual value. * * @returns An object representing the expected type assertion. */ <Actual>(): ExpectTypeOf<Actual, { positive: true; branded: false; }>; }; /** * Similar to Jest's `expect`, but with type-awareness. * Gives you access to a number of type-matchers that let you make assertions about the * form of a reference or generic type parameter. * * @example * ```ts * import { foo, bar } from '../foo' * import { expectTypeOf } from 'expect-type' * * test('foo types', () => { * // make sure `foo` has type { a: number } * expectTypeOf(foo).toMatchTypeOf({ a: 1 }) * expectTypeOf(foo).toHaveProperty('a').toBeNumber() * * // make sure `bar` is a function taking a string: * expectTypeOf(bar).parameter(0).toBeString() * expectTypeOf(bar).returns.not.toBeAny() * }) * ``` * * @description * See the [full docs](https://npmjs.com/package/expect-type#documentation) for lots more examples. */ export declare const expectTypeOf: _ExpectTypeOf;