diff --git a/docs/test/writing.md b/docs/test/writing.md index 6ecb625de2..f19ac7bf55 100644 --- a/docs/test/writing.md +++ b/docs/test/writing.md @@ -426,6 +426,54 @@ test("exactly two assertions", () => { This helps ensure all your assertions run, especially in complex async code with multiple code paths. +## Type Testing + +Bun includes `expectTypeOf` for testing typescript types, compatible with Vitest. + +### expectTypeOf + +{% callout %} + +**Note** — These functions are no-ops at runtime - you need to run TypeScript separately to verify the type checks. + +{% endcallout %} + +The `expectTypeOf` function provides type-level assertions that are checked by TypeScript's type checker. **Important**: + +To test your types: + +1. Write your type assertions using `expectTypeOf` +2. Run `bunx tsc --noEmit` to check that your types are correct + +```ts +import { expectTypeOf } from "bun:test"; + +// Basic type assertions +expectTypeOf().toEqualTypeOf(); +expectTypeOf(123).toBeNumber(); +expectTypeOf("hello").toBeString(); + +// Object type matching +expectTypeOf({ a: 1, b: "hello" }).toMatchObjectType<{ a: number }>(); + +// Function types +function greet(name: string): string { + return `Hello ${name}`; +} + +expectTypeOf(greet).toBeFunction(); +expectTypeOf(greet).parameters.toEqualTypeOf<[string]>(); +expectTypeOf(greet).returns.toEqualTypeOf(); + +// Array types +expectTypeOf([1, 2, 3]).items.toBeNumber(); + +// Promise types +expectTypeOf(Promise.resolve(42)).resolves.toBeNumber(); +``` + +For full documentation on expectTypeOf matchers, see the [API Reference](/reference/bun/test/expectTypeOf) + ## Matchers Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825). diff --git a/packages/bun-types/package.json b/packages/bun-types/package.json index 4ab5abba4a..b44467fddd 100644 --- a/packages/bun-types/package.json +++ b/packages/bun-types/package.json @@ -10,6 +10,7 @@ }, "files": [ "./*.d.ts", + "vendor/**/*.d.ts", "docs/**/*.md", "docs/*.md", "CLAUDE.md", diff --git a/packages/bun-types/test-globals.d.ts b/packages/bun-types/test-globals.d.ts index b5c5d3ed4a..4f38635206 100644 --- a/packages/bun-types/test-globals.d.ts +++ b/packages/bun-types/test-globals.d.ts @@ -10,6 +10,7 @@ declare var test: typeof import("bun:test").test; declare var it: typeof import("bun:test").it; declare var describe: typeof import("bun:test").describe; declare var expect: typeof import("bun:test").expect; +declare var expectTypeOf: typeof import("bun:test").expectTypeOf; declare var beforeAll: typeof import("bun:test").beforeAll; declare var beforeEach: typeof import("bun:test").beforeEach; declare var afterEach: typeof import("bun:test").afterEach; diff --git a/packages/bun-types/test.d.ts b/packages/bun-types/test.d.ts index c02e72f1d7..ffff77134b 100644 --- a/packages/bun-types/test.d.ts +++ b/packages/bun-types/test.d.ts @@ -2182,4 +2182,6 @@ declare module "bun:test" { export type UnknownFunction = (...args: unknown[]) => unknown; } + + export const expectTypeOf: typeof import("./vendor/expect-type").expectTypeOf; } diff --git a/packages/bun-types/vendor/expect-type/branding.d.ts b/packages/bun-types/vendor/expect-type/branding.d.ts new file mode 100644 index 0000000000..e0dcb2dcdb --- /dev/null +++ b/packages/bun-types/vendor/expect-type/branding.d.ts @@ -0,0 +1,283 @@ +/* + Copyright 2024 Misha Kaletsky + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +*/ + +import type { ConstructorOverloadParameters, NumOverloads, OverloadsInfoUnion } from "./overloads"; +import type { + IsAny, + IsNever, + IsUnknown, + MutuallyExtends, + OptionalKeys, + ReadonlyKeys, + RequiredKeys, + UnionToTuple, +} from "./utils"; +/** + * Represents a deeply branded type. + * + * Recursively walk a type and replace it with a branded type related to the + * original. This is useful for equality-checking stricter than + * `A extends B ? B extends A ? true : false : false`, because it detects the + * difference between a few edge-case types that vanilla TypeScript + * doesn't by default: + * - `any` vs `unknown` + * - `{ readonly a: string }` vs `{ a: string }` + * - `{ a?: string }` vs `{ a: string | undefined }` + * + * __Note__: not very performant for complex types - this should only be used + * when you know you need it. If doing an equality check, it's almost always + * better to use {@linkcode StrictEqualUsingTSInternalIdenticalToOperator}. + */ +export type DeepBrand = + IsNever extends true + ? { + type: "never"; + } + : IsAny extends true + ? { + type: "any"; + } + : IsUnknown extends true + ? { + type: "unknown"; + } + : T extends string | number | boolean | symbol | bigint | null | undefined | void + ? { + type: "primitive"; + value: T; + } + : T extends new (...args: any[]) => any + ? { + type: "constructor"; + params: ConstructorOverloadParameters; + instance: DeepBrand any>>>; + } + : T extends (...args: infer P) => infer R + ? NumOverloads extends 1 + ? { + type: "function"; + params: DeepBrand

; + return: DeepBrand; + this: DeepBrand>; + props: DeepBrand>; + } + : UnionToTuple> extends infer OverloadsTuple + ? { + type: "overloads"; + overloads: { + [K in keyof OverloadsTuple]: DeepBrand; + }; + } + : never + : T extends any[] + ? { + type: "array"; + items: { + [K in keyof T]: T[K]; + }; + } + : { + type: "object"; + properties: { + [K in keyof T]: DeepBrand; + }; + readonly: ReadonlyKeys; + required: RequiredKeys; + optional: OptionalKeys; + constructorParams: DeepBrand>; + }; +/** + * Checks if two types are strictly equal using branding. + */ +export type StrictEqualUsingBranding = MutuallyExtends, DeepBrand>; diff --git a/packages/bun-types/vendor/expect-type/index.d.ts b/packages/bun-types/vendor/expect-type/index.d.ts new file mode 100644 index 0000000000..d12bbbc196 --- /dev/null +++ b/packages/bun-types/vendor/expect-type/index.d.ts @@ -0,0 +1,1207 @@ +/* + Copyright 2024 Misha Kaletsky + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +*/ + +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 + 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 {@linkcode Expected | expected type} are not allowed to be missing on the {@linkcode Actual | actual type}. + * + * @example + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toMatchObjectType<{ a: number }>() + * + * expectTypeOf({ a: 1, b: 1 }).not.toMatchObjectType<{ a: number; c?: number }>() + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + toMatchObjectType: < + Expected extends IsUnion extends true + ? "toMatchObject does not support union types" + : Not>> extends true + ? "toMatchObject only supports object types" + : StrictEqualUsingTSInternalIdenticalToOperator, Expected> extends true + ? unknown + : MismatchInfo, Expected>, + >( + ...MISMATCH: MismatchArgs< + StrictEqualUsingTSInternalIdenticalToOperator, Expected>, + true + > + ) => true; + /** + * 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 + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toExtend<{ a: number }>() + * + * expectTypeOf({ a: 1 }).not.toExtend<{ b: number }>() + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + toExtend: extends true ? unknown : MismatchInfo>( + ...MISMATCH: MismatchArgs, 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() + * + * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```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 extends true + ? unknown + : MismatchInfo, + >( + 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, 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() + * + * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```ts + * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) + * + * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + < + Expected extends StrictEqualUsingTSInternalIdenticalToOperator extends true + ? unknown + : MismatchInfo, + >( + ...MISMATCH: MismatchArgs, true> + ): true; + }; + /** + * @deprecated Use either {@linkcode toMatchObjectType} or {@linkcode toExtend} instead + * + * - Use {@linkcode toMatchObjectType} to perform a strict check on a subset of your type's keys + * - Use {@linkcode toExtend} to check if your type extends the expected type + */ + toMatchTypeOf: { + /** + * @deprecated Use either {@linkcode toMatchObjectType} or {@linkcode toExtend} instead + * + * - Use {@linkcode toMatchObjectType} to perform a strict check on a subset of your type's keys + * - Use {@linkcode 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```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`. + */ + extends true ? unknown : MismatchInfo>( + 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, true> + ): true; + /** + * @deprecated Use either {@linkcode toMatchObjectType} or {@linkcode toExtend} instead + * + * - Use {@linkcode toMatchObjectType} to perform a strict check on a subset of your type's keys + * - Use {@linkcode 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + extends true ? unknown : MismatchInfo>( + ...MISMATCH: MismatchArgs, true> + ): true; + }; + /** + * Checks whether an object has a given property. + * + * @example + * check that properties exist + * ```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: ( + key: KeyType, + ...MISMATCH: MismatchArgs, true> + ) => KeyType extends keyof Actual ? PositiveExpectTypeOf : true; + /** + * Inverts the result of the following assertions. + * + * @example + * ```ts + * expectTypeOf({ a: 1 }).not.toMatchTypeOf({ b: 1 }) + * ``` + */ + not: NegativeExpectTypeOf; + /** + * 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() + * + * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```ts + * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) + * + * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + toEqualTypeOf: < + Expected extends StrictEqualUsingBranding extends true + ? unknown + : MismatchInfo, + >( + ...MISMATCH: MismatchArgs, true> + ) => true; + }; +} +/** + * Represents the negative expectation type for the {@linkcode Actual} type. + */ +export interface NegativeExpectTypeOf + 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`. + * + * **Note**: optional properties on the {@linkcode Expected | expected type} are not allowed to be missing on the {@linkcode Actual | actual type}. + * + * @example + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toMatchObjectType<{ a: number }>() + * + * expectTypeOf({ a: 1, b: 1 }).not.toMatchObjectType<{ a: number; c?: number }>() + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + toMatchObjectType: ( + ...MISMATCH: MismatchArgs< + StrictEqualUsingTSInternalIdenticalToOperator, Expected>, + false + > + ) => true; + /** + * Check if your type extends the expected type + * + * 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 + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toExtend<{ a: number }>()] + * + * expectTypeOf({ a: 1 }).not.toExtend<{ b: number }>() + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + toExtend(...MISMATCH: MismatchArgs, 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() + * + * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```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`. + */ + ( + value: Expected & AValue, + ...MISMATCH: MismatchArgs, 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: number }>() + * + * expectTypeOf({ a: 1, b: 1 }).not.toEqualTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```ts + * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 1 }) + * + * expectTypeOf({ a: 1 }).toEqualTypeOf({ a: 2 }) + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + (...MISMATCH: MismatchArgs, false>): true; + }; + /** + * @deprecated Use either {@linkcode toMatchObjectType} or {@linkcode toExtend} instead + * + * - Use {@linkcode toMatchObjectType} to perform a strict check on a subset of your type's keys + * - Use {@linkcode toExtend} to check if your type extends the expected type + */ + toMatchTypeOf: { + /** + * @deprecated Use either {@linkcode toMatchObjectType} or {@linkcode toExtend} instead + * + * - Use {@linkcode toMatchObjectType} to perform a strict check on a subset of your type's keys + * - Use {@linkcode toExtend} to check if your type extends the expected type + * + * 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```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`. + */ + ( + 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, false> + ): true; + /** + * @deprecated Use either {@linkcode toMatchObjectType} or {@linkcode toExtend} instead + * + * - Use {@linkcode toMatchObjectType} to perform a strict check on a subset of your type's keys + * - Use {@linkcode toExtend} to check if your type extends the expected type + * + * 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 + * Using generic type argument syntax + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf<{ a: number }>() + * ``` + * + * @example + * Using inferred type syntax by passing a value + * ```ts + * expectTypeOf({ a: 1, b: 1 }).toMatchTypeOf({ a: 2 }) + * ``` + * + * @param MISMATCH - The mismatch arguments. + * @returns `true`. + */ + (...MISMATCH: MismatchArgs, false>): true; + }; + /** + * Checks whether an object has a given property. + * + * @example + * check that properties exist + * ```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: ( + key: KeyType, + ...MISMATCH: MismatchArgs, 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 : NegativeExpectTypeOf; +/** + * 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, Options>; + /** + * Checks whether the type of the value is `unknown`. + */ + toBeUnknown: Scolder, Options>; + /** + * Checks whether the type of the value is `never`. + */ + toBeNever: Scolder, Options>; + /** + * Checks whether the type of the value is `function`. + */ + toBeFunction: Scolder, Options>; + /** + * Checks whether the type of the value is `object`. + */ + toBeObject: Scolder, Options>; + /** + * Checks whether the type of the value is an {@linkcode Array}. + */ + toBeArray: Scolder, Options>; + /** + * Checks whether the type of the value is `number`. + */ + toBeNumber: Scolder, Options>; + /** + * Checks whether the type of the value is `string`. + */ + toBeString: Scolder, Options>; + /** + * Checks whether the type of the value is `boolean`. + */ + toBeBoolean: Scolder, Options>; + /** + * Checks whether the type of the value is `void`. + */ + toBeVoid: Scolder, Options>; + /** + * Checks whether the type of the value is `symbol`. + */ + toBeSymbol: Scolder, Options>; + /** + * Checks whether the type of the value is `null`. + */ + toBeNull: Scolder, Options>; + /** + * Checks whether the type of the value is `undefined`. + */ + toBeUndefined: Scolder, Options>; + /** + * Checks whether the type of the value is `null` or `undefined`. + */ + toBeNullable: Scolder, 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: (fn: (value: Actual) => T) => ExpectTypeOf; + /** + * Checks whether the type of the value is **`bigint`**. + * + * @example + * #### Distinguish between **`number`** and **`bigint`** + * + * ```ts + * import { expectTypeOf } from 'expect-type' + * + * const aVeryBigInteger = 10n ** 100n + * + * expectTypeOf(aVeryBigInteger).not.toBeNumber() + * + * expectTypeOf(aVeryBigInteger).toBeBigInt() + * ``` + * + * @since 1.1.0 + */ + toBeBigInt: Scolder, 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: Args + ) => ExpectTypeOf, 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: Args) => true + : never; + /** + * Equivalent to the {@linkcode Extract} utility type. + * Helps narrow down complex union types. + * + * @example + * ```ts + * type ResponsiveProp = T | T[] | { xs?: T; sm?: T; md?: T } + * + * interface CSSProperties { + * margin?: string + * padding?: string + * } + * + * function getResponsiveProp(_props: T): ResponsiveProp { + * 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() // extracts an array from a union + * .toEqualTypeOf() + * ``` + * + * __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) => ExpectTypeOf, Options>; + /** + * Equivalent to the {@linkcode Exclude} utility type. + * Removes types from a union. + * + * @example + * ```ts + * type ResponsiveProp = T | T[] | { xs?: T; sm?: T; md?: T } + * + * interface CSSProperties { + * margin?: string + * padding?: string + * } + * + * function getResponsiveProp(_props: T): ResponsiveProp { + * return {} + * } + * + * const cssProperties: CSSProperties = { margin: '1px', padding: '2px' } + * + * expectTypeOf(getResponsiveProp(cssProperties)) + * .exclude() + * .exclude<{ xs?: unknown }>() // or just `.exclude()` + * .toEqualTypeOf() + * ``` + */ + exclude: (v?: V) => ExpectTypeOf, 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() + * .pick<'name'>() + * .toEqualTypeOf<{ name: string }>() + * ``` + * + * @param keyToPick - The property key to pick. + * @returns The type after picking the property. + */ + pick: (keyToPick?: KeyToPick) => ExpectTypeOf, 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().omit<'name'>().toEqualTypeOf<{ age: number }>() + * ``` + * + * @param keyToOmit - The property key to omit. + * @returns The type after omitting the property. + */ + omit: )>( + keyToOmit?: KeyToOmit, + ) => ExpectTypeOf, 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: Index) => ExpectTypeOf[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, 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, 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, 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 : 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, 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 extends PromiseLike + * ? ResolvedType + * : never + * ``` + */ + resolves: Actual extends PromiseLike ? ExpectTypeOf : never; + /** + * Extracts array item type to perform assertions on. + * + * @example + * ```ts + * expectTypeOf([1, 2, 3]).items.toEqualTypeOf() + * + * expectTypeOf([1, 2, 3]).items.not.toEqualTypeOf() + * ``` + * + * __Type Equivalent__: + * ```ts + * type Items = ArrayType extends ArrayLike + * ? ItemType + * : never + * ``` + */ + items: Actual extends ArrayLike ? ExpectTypeOf : 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 : 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 + : 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): 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. + */ + (): 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; diff --git a/packages/bun-types/vendor/expect-type/messages.d.ts b/packages/bun-types/vendor/expect-type/messages.d.ts new file mode 100644 index 0000000000..cc6b05f297 --- /dev/null +++ b/packages/bun-types/vendor/expect-type/messages.d.ts @@ -0,0 +1,395 @@ +/* + Copyright 2024 Misha Kaletsky + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +*/ + +import type { StrictEqualUsingBranding } from "./branding"; +import type { And, Extends, ExtendsExcludingAnyOrNever, IsAny, IsNever, IsUnknown, Not, UsefulKeys } from "./utils"; +/** + * Determines the printable type representation for a given type. + */ +export type PrintType = + IsUnknown extends true + ? "unknown" + : IsNever extends true + ? "never" + : IsAny extends true + ? never + : boolean extends T + ? "boolean" + : T extends boolean + ? `literal boolean: ${T}` + : string extends T + ? "string" + : T extends string + ? `literal string: ${T}` + : number extends T + ? "number" + : T extends number + ? `literal number: ${T}` + : bigint extends T + ? "bigint" + : T extends bigint + ? `literal bigint: ${T}` + : T extends null + ? "null" + : T extends undefined + ? "undefined" + : T extends (...args: any[]) => any + ? "function" + : "..."; +/** + * Helper for showing end-user a hint why their type assertion is failing. + * This swaps "leaf" types with a literal message about what the actual and + * expected types are. Needs to check for `Not>` because + * otherwise `LeafTypeOf` returns `never`, which extends everything 🤔 + */ +export type MismatchInfo = + And<[Extends, "...">, Not>]> extends true + ? And<[Extends, Extends]> extends true + ? Array[number], Extract[number]>> + : { + [K in UsefulKeys | UsefulKeys]: MismatchInfo< + K extends keyof Actual ? Actual[K] : never, + K extends keyof Expected ? Expected[K] : never + >; + } + : StrictEqualUsingBranding extends true + ? Actual + : `Expected: ${PrintType}, Actual: ${PrintType>}`; +/** + * @internal + */ +declare const inverted: unique symbol; +/** + * @internal + */ +type Inverted = { + [inverted]: T; +}; +/** + * @internal + */ +declare const expectNull: unique symbol; +export type ExpectNull = { + [expectNull]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectUndefined: unique symbol; +export type ExpectUndefined = { + [expectUndefined]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectNumber: unique symbol; +export type ExpectNumber = { + [expectNumber]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectString: unique symbol; +export type ExpectString = { + [expectString]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectBoolean: unique symbol; +export type ExpectBoolean = { + [expectBoolean]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectVoid: unique symbol; +export type ExpectVoid = { + [expectVoid]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectFunction: unique symbol; +export type ExpectFunction = { + [expectFunction]: T; + result: ExtendsExcludingAnyOrNever any>; +}; +/** + * @internal + */ +declare const expectObject: unique symbol; +export type ExpectObject = { + [expectObject]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectArray: unique symbol; +export type ExpectArray = { + [expectArray]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectSymbol: unique symbol; +export type ExpectSymbol = { + [expectSymbol]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * @internal + */ +declare const expectAny: unique symbol; +export type ExpectAny = { + [expectAny]: T; + result: IsAny; +}; +/** + * @internal + */ +declare const expectUnknown: unique symbol; +export type ExpectUnknown = { + [expectUnknown]: T; + result: IsUnknown; +}; +/** + * @internal + */ +declare const expectNever: unique symbol; +export type ExpectNever = { + [expectNever]: T; + result: IsNever; +}; +/** + * @internal + */ +declare const expectNullable: unique symbol; +export type ExpectNullable = { + [expectNullable]: T; + result: Not>>; +}; +/** + * @internal + */ +declare const expectBigInt: unique symbol; +export type ExpectBigInt = { + [expectBigInt]: T; + result: ExtendsExcludingAnyOrNever; +}; +/** + * Checks if the result of an expecter matches the specified options, and + * resolves to a fairly readable error message if not. + */ +export type Scolder< + Expecter extends { + result: boolean; + }, + Options extends { + positive: boolean; + }, +> = Expecter["result"] extends Options["positive"] + ? () => true + : Options["positive"] extends true + ? Expecter + : Inverted; +export {}; diff --git a/packages/bun-types/vendor/expect-type/overloads.d.ts b/packages/bun-types/vendor/expect-type/overloads.d.ts new file mode 100644 index 0000000000..ec14741e63 --- /dev/null +++ b/packages/bun-types/vendor/expect-type/overloads.d.ts @@ -0,0 +1,669 @@ +/* + Copyright 2024 Misha Kaletsky + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +*/ + +import type { + IsNever, + StrictEqualUsingTSInternalIdenticalToOperator, + UnionToIntersection, + UnionToTuple, +} from "./utils"; +/** + * The simple(ish) way to get overload info from a function + * {@linkcode FunctionType}. Recent versions of TypeScript will match any + * function against a generic 10-overload type, filling in slots with + * duplicates of the function. So, we can just match against a single type + * and get all the overloads. + * + * For older versions of TypeScript, we'll need to painstakingly do + * ten separate matches. + */ +export type TSPost53OverloadsInfoUnion = FunctionType extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + (...args: infer A4): infer R4; + (...args: infer A5): infer R5; + (...args: infer A6): infer R6; + (...args: infer A7): infer R7; + (...args: infer A8): infer R8; + (...args: infer A9): infer R9; + (...args: infer A10): infer R10; +} + ? + | ((...p: A1) => R1) + | ((...p: A2) => R2) + | ((...p: A3) => R3) + | ((...p: A4) => R4) + | ((...p: A5) => R5) + | ((...p: A6) => R6) + | ((...p: A7) => R7) + | ((...p: A8) => R8) + | ((...p: A9) => R9) + | ((...p: A10) => R10) + : never; +/** + * A function with `unknown` parameters and return type. + */ +export type UnknownFunction = (...args: unknown[]) => unknown; +/** + * `true` iff {@linkcode FunctionType} is + * equivalent to `(...args: unknown[]) => unknown`, + * which is what an overload variant looks like for a non-existent overload. + * This is useful because older versions of TypeScript end up with + * 9 "useless" overloads and one real one for parameterless/generic functions. + * + * @see {@link https://github.com/microsoft/TypeScript/issues/28867 | Related} + */ +export type IsUselessOverloadInfo = StrictEqualUsingTSInternalIdenticalToOperator< + FunctionType, + UnknownFunction +>; +/** + * Old versions of TypeScript can sometimes seem to refuse to separate out + * union members unless you put them each in a pointless tuple and add an + * extra `infer X` expression. There may be a better way to work around this + * problem, but since it's not a problem in newer versions of TypeScript, + * it's not a priority right now. + */ +export type Tuplify = Union extends infer X ? [X] : never; +/** + * For older versions of TypeScript, we need two separate workarounds + * to get overload info. First, we need need to use + * {@linkcode DecreasingOverloadsInfoUnion} to get the overload info for + * functions with 1-10 overloads. Then, we need to filter out the + * "useless" overloads that are present in older versions of TypeScript, + * for parameterless functions. To do this we use + * {@linkcode IsUselessOverloadInfo} to remove useless overloads. + * + * @see {@link https://github.com/microsoft/TypeScript/issues/28867 | Related} + */ +export type TSPre53OverloadsInfoUnion = + Tuplify> extends infer Tup + ? Tup extends [infer Fn] + ? IsUselessOverloadInfo extends true + ? never + : Fn + : never + : never; +/** + * For versions of TypeScript below 5.3, we need to check for 10 overloads, + * then 9, then 8, etc., to get a union of the overload variants. + */ +export type DecreasingOverloadsInfoUnion = F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + (...args: infer A4): infer R4; + (...args: infer A5): infer R5; + (...args: infer A6): infer R6; + (...args: infer A7): infer R7; + (...args: infer A8): infer R8; + (...args: infer A9): infer R9; + (...args: infer A10): infer R10; +} + ? + | ((...p: A1) => R1) + | ((...p: A2) => R2) + | ((...p: A3) => R3) + | ((...p: A4) => R4) + | ((...p: A5) => R5) + | ((...p: A6) => R6) + | ((...p: A7) => R7) + | ((...p: A8) => R8) + | ((...p: A9) => R9) + | ((...p: A10) => R10) + : F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + (...args: infer A4): infer R4; + (...args: infer A5): infer R5; + (...args: infer A6): infer R6; + (...args: infer A7): infer R7; + (...args: infer A8): infer R8; + (...args: infer A9): infer R9; + } + ? + | ((...p: A1) => R1) + | ((...p: A2) => R2) + | ((...p: A3) => R3) + | ((...p: A4) => R4) + | ((...p: A5) => R5) + | ((...p: A6) => R6) + | ((...p: A7) => R7) + | ((...p: A8) => R8) + | ((...p: A9) => R9) + : F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + (...args: infer A4): infer R4; + (...args: infer A5): infer R5; + (...args: infer A6): infer R6; + (...args: infer A7): infer R7; + (...args: infer A8): infer R8; + } + ? + | ((...p: A1) => R1) + | ((...p: A2) => R2) + | ((...p: A3) => R3) + | ((...p: A4) => R4) + | ((...p: A5) => R5) + | ((...p: A6) => R6) + | ((...p: A7) => R7) + | ((...p: A8) => R8) + : F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + (...args: infer A4): infer R4; + (...args: infer A5): infer R5; + (...args: infer A6): infer R6; + (...args: infer A7): infer R7; + } + ? + | ((...p: A1) => R1) + | ((...p: A2) => R2) + | ((...p: A3) => R3) + | ((...p: A4) => R4) + | ((...p: A5) => R5) + | ((...p: A6) => R6) + | ((...p: A7) => R7) + : F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + (...args: infer A4): infer R4; + (...args: infer A5): infer R5; + (...args: infer A6): infer R6; + } + ? + | ((...p: A1) => R1) + | ((...p: A2) => R2) + | ((...p: A3) => R3) + | ((...p: A4) => R4) + | ((...p: A5) => R5) + | ((...p: A6) => R6) + : F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + (...args: infer A4): infer R4; + (...args: infer A5): infer R5; + } + ? ((...p: A1) => R1) | ((...p: A2) => R2) | ((...p: A3) => R3) | ((...p: A4) => R4) | ((...p: A5) => R5) + : F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + (...args: infer A4): infer R4; + } + ? ((...p: A1) => R1) | ((...p: A2) => R2) | ((...p: A3) => R3) | ((...p: A4) => R4) + : F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + (...args: infer A3): infer R3; + } + ? ((...p: A1) => R1) | ((...p: A2) => R2) | ((...p: A3) => R3) + : F extends { + (...args: infer A1): infer R1; + (...args: infer A2): infer R2; + } + ? ((...p: A1) => R1) | ((...p: A2) => R2) + : F extends (...args: infer A1) => infer R1 + ? (...p: A1) => R1 + : never; +/** + * Get a union of overload variants for a function {@linkcode FunctionType}. + * Does a check for whether we can do the one-shot + * 10-overload matcher (which works for ts\>5.3), and if not, + * falls back to the more complicated utility. + */ +export type OverloadsInfoUnion = + IsNever 2>> extends true + ? TSPre53OverloadsInfoUnion + : TSPost53OverloadsInfoUnion; +/** + * Allows inferring any function using the `infer` keyword. + */ +export type InferFunctionType any> = FunctionType; +/** + * A union type of the parameters allowed for any + * overload of function {@linkcode FunctionType}. + */ +export type OverloadParameters = + OverloadsInfoUnion extends InferFunctionType ? Parameters : never; +/** + * A union type of the return types for any overload of + * function {@linkcode FunctionType}. + */ +export type OverloadReturnTypes = + OverloadsInfoUnion extends InferFunctionType ? ReturnType : never; +/** + * Takes an overload variants {@linkcode Union}, + * produced from {@linkcode OverloadsInfoUnion} and rejects + * the ones incompatible with parameters {@linkcode Args}. + */ +export type SelectOverloadsInfo = + Union extends InferFunctionType ? (Args extends Parameters ? Fn : never) : never; +/** + * Creates a new overload (an intersection type) from an existing one, + * which only includes variant(s) which can accept + * {@linkcode Args} as parameters. + */ +export type OverloadsNarrowedByParameters< + FunctionType, + Args extends OverloadParameters, +> = UnionToIntersection, Args>>; +/** + * The simple(ish) way to get overload info from a constructor + * {@linkcode ConstructorType}. Recent versions of TypeScript will match any + * constructor against a generic 10-overload type, filling in slots with + * duplicates of the constructor. So, we can just match against a single type + * and get all the overloads. + * + * For older versions of TypeScript, + * we'll need to painstakingly do ten separate matches. + */ +export type TSPost53ConstructorOverloadsInfoUnion = ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + new (...args: infer A4): infer R4; + new (...args: infer A5): infer R5; + new (...args: infer A6): infer R6; + new (...args: infer A7): infer R7; + new (...args: infer A8): infer R8; + new (...args: infer A9): infer R9; + new (...args: infer A10): infer R10; +} + ? + | (new (...p: A1) => R1) + | (new (...p: A2) => R2) + | (new (...p: A3) => R3) + | (new (...p: A4) => R4) + | (new (...p: A5) => R5) + | (new (...p: A6) => R6) + | (new (...p: A7) => R7) + | (new (...p: A8) => R8) + | (new (...p: A9) => R9) + | (new (...p: A10) => R10) + : never; +/** + * A constructor function with `unknown` parameters and return type. + */ +export type UnknownConstructor = new (...args: unknown[]) => unknown; +/** + * Same as {@linkcode IsUselessOverloadInfo}, but for constructors. + */ +export type IsUselessConstructorOverloadInfo = StrictEqualUsingTSInternalIdenticalToOperator< + FunctionType, + UnknownConstructor +>; +/** + * For older versions of TypeScript, we need two separate workarounds to + * get constructor overload info. First, we need need to use + * {@linkcode DecreasingConstructorOverloadsInfoUnion} to get the overload + * info for constructors with 1-10 overloads. Then, we need to filter out the + * "useless" overloads that are present in older versions of TypeScript, + * for parameterless constructors. To do this we use + * {@linkcode IsUselessConstructorOverloadInfo} to remove useless overloads. + * + * @see {@link https://github.com/microsoft/TypeScript/issues/28867 | Related} + */ +export type TSPre53ConstructorOverloadsInfoUnion = + Tuplify> extends infer Tup + ? Tup extends [infer Ctor] + ? IsUselessConstructorOverloadInfo extends true + ? never + : Ctor + : never + : never; +/** + * For versions of TypeScript below 5.3, we need to check for 10 overloads, + * then 9, then 8, etc., to get a union of the overload variants. + */ +export type DecreasingConstructorOverloadsInfoUnion = ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + new (...args: infer A4): infer R4; + new (...args: infer A5): infer R5; + new (...args: infer A6): infer R6; + new (...args: infer A7): infer R7; + new (...args: infer A8): infer R8; + new (...args: infer A9): infer R9; + new (...args: infer A10): infer R10; +} + ? + | (new (...p: A1) => R1) + | (new (...p: A2) => R2) + | (new (...p: A3) => R3) + | (new (...p: A4) => R4) + | (new (...p: A5) => R5) + | (new (...p: A6) => R6) + | (new (...p: A7) => R7) + | (new (...p: A8) => R8) + | (new (...p: A9) => R9) + | (new (...p: A10) => R10) + : ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + new (...args: infer A4): infer R4; + new (...args: infer A5): infer R5; + new (...args: infer A6): infer R6; + new (...args: infer A7): infer R7; + new (...args: infer A8): infer R8; + new (...args: infer A9): infer R9; + } + ? + | (new (...p: A1) => R1) + | (new (...p: A2) => R2) + | (new (...p: A3) => R3) + | (new (...p: A4) => R4) + | (new (...p: A5) => R5) + | (new (...p: A6) => R6) + | (new (...p: A7) => R7) + | (new (...p: A8) => R8) + | (new (...p: A9) => R9) + : ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + new (...args: infer A4): infer R4; + new (...args: infer A5): infer R5; + new (...args: infer A6): infer R6; + new (...args: infer A7): infer R7; + new (...args: infer A8): infer R8; + } + ? + | (new (...p: A1) => R1) + | (new (...p: A2) => R2) + | (new (...p: A3) => R3) + | (new (...p: A4) => R4) + | (new (...p: A5) => R5) + | (new (...p: A6) => R6) + | (new (...p: A7) => R7) + | (new (...p: A8) => R8) + : ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + new (...args: infer A4): infer R4; + new (...args: infer A5): infer R5; + new (...args: infer A6): infer R6; + new (...args: infer A7): infer R7; + } + ? + | (new (...p: A1) => R1) + | (new (...p: A2) => R2) + | (new (...p: A3) => R3) + | (new (...p: A4) => R4) + | (new (...p: A5) => R5) + | (new (...p: A6) => R6) + | (new (...p: A7) => R7) + : ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + new (...args: infer A4): infer R4; + new (...args: infer A5): infer R5; + new (...args: infer A6): infer R6; + } + ? + | (new (...p: A1) => R1) + | (new (...p: A2) => R2) + | (new (...p: A3) => R3) + | (new (...p: A4) => R4) + | (new (...p: A5) => R5) + | (new (...p: A6) => R6) + : ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + new (...args: infer A4): infer R4; + new (...args: infer A5): infer R5; + } + ? + | (new (...p: A1) => R1) + | (new (...p: A2) => R2) + | (new (...p: A3) => R3) + | (new (...p: A4) => R4) + | (new (...p: A5) => R5) + : ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + new (...args: infer A4): infer R4; + } + ? (new (...p: A1) => R1) | (new (...p: A2) => R2) | (new (...p: A3) => R3) | (new (...p: A4) => R4) + : ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + new (...args: infer A3): infer R3; + } + ? (new (...p: A1) => R1) | (new (...p: A2) => R2) | (new (...p: A3) => R3) + : ConstructorType extends { + new (...args: infer A1): infer R1; + new (...args: infer A2): infer R2; + } + ? (new (...p: A1) => R1) | (new (...p: A2) => R2) + : ConstructorType extends new (...args: infer A1) => infer R1 + ? new (...p: A1) => R1 + : never; +/** + * Get a union of overload variants for a constructor + * {@linkcode ConstructorType}. Does a check for whether we can do the + * one-shot 10-overload matcher (which works for ts\>5.3), and if not, + * falls back to the more complicated utility. + */ +export type ConstructorOverloadsUnion = + IsNever any>> extends true + ? TSPre53ConstructorOverloadsInfoUnion + : TSPost53ConstructorOverloadsInfoUnion; +/** + * Allows inferring any constructor using the `infer` keyword. + */ +export type InferConstructor any> = ConstructorType; +/** + * A union type of the parameters allowed for any overload + * of constructor {@linkcode ConstructorType}. + */ +export type ConstructorOverloadParameters = + ConstructorOverloadsUnion extends InferConstructor ? ConstructorParameters : never; +/** + * Calculates the number of overloads for a given function type. + */ +export type NumOverloads = UnionToTuple>["length"]; diff --git a/packages/bun-types/vendor/expect-type/utils.d.ts b/packages/bun-types/vendor/expect-type/utils.d.ts new file mode 100644 index 0000000000..56cc074159 --- /dev/null +++ b/packages/bun-types/vendor/expect-type/utils.d.ts @@ -0,0 +1,431 @@ +/* + Copyright 2024 Misha Kaletsky + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +*/ + +/** + * Negates a boolean type. + */ +export type Not = T extends true ? false : true; +/** + * Returns `true` if at least one of the types in the + * {@linkcode Types} array is `true`, otherwise returns `false`. + */ +export type Or = Types[number] extends false ? false : true; +/** + * Checks if all the boolean types in the {@linkcode Types} array are `true`. + */ +export type And = Types[number] extends true ? true : false; +/** + * Represents an equality type that returns {@linkcode Right} if + * {@linkcode Left} is `true`, + * otherwise returns the negation of {@linkcode Right}. + */ +export type Eq = Left extends true ? Right : Not; +/** + * Represents the exclusive OR operation on a tuple of boolean types. + * Returns `true` if exactly one of the boolean types is `true`, + * otherwise returns `false`. + */ +export type Xor = Not>; +/** + * @internal + */ +declare const secret: unique symbol; +/** + * @internal + */ +type Secret = typeof secret; +/** + * Checks if the given type is `never`. + */ +export type IsNever = [T] extends [never] ? true : false; +/** + * Checks if the given type is `any`. + */ +export type IsAny = [T] extends [Secret] ? Not> : false; +/** + * Determines if the given type is `unknown`. + */ +export type IsUnknown = [unknown] extends [T] ? Not> : false; +/** + * Determines if a type is either `never` or `any`. + */ +export type IsNeverOrAny = Or<[IsNever, IsAny]>; +/** + * Subjective "useful" keys from a type. For objects it's just `keyof` but for + * tuples/arrays it's the number keys. + * + * @example + * ```ts + * UsefulKeys<{ a: 1; b: 2 }> // 'a' | 'b' + * + * UsefulKeys<['a', 'b']> // '0' | '1' + * + * UsefulKeys // number + * ``` + */ +export type UsefulKeys = T extends any[] + ? { + [K in keyof T]: K; + }[number] + : keyof T; +/** + * Extracts the keys from a type that are required (not optional). + */ +export type RequiredKeys = Extract< + { + [K in keyof T]-?: {} extends Pick ? never : K; + }[keyof T], + keyof T +>; +/** + * Gets the keys of an object type that are optional. + */ +export type OptionalKeys = Exclude>; +/** + * Extracts the keys from a type that are not `readonly`. + */ +export type ReadonlyKeys = Extract< + { + [K in keyof T]-?: ReadonlyEquivalent< + { + [_K in K]: T[K]; + }, + { + -readonly [_K in K]: T[K]; + } + > extends true + ? never + : K; + }[keyof T], + keyof T +>; +/** + * Determines if two types, are equivalent in a `readonly` manner. + * + * @internal + */ +type ReadonlyEquivalent = Extends<() => T extends X ? true : false, () => T extends Y ? true : false>; +/** + * Checks if one type extends another. Note: this is not quite the same as `Left extends Right` because: + * 1. If either type is `never`, the result is `true` iff the other type is also `never`. + * 2. Types are wrapped in a 1-tuple so that union types are not distributed - instead we consider `string | number` to _not_ extend `number`. If we used `Left extends Right` directly you would get `Extends` => `false | true` => `boolean`. + */ +export type Extends = IsNever extends true ? IsNever : [Left] extends [Right] ? true : false; +/** + * Checks if the {@linkcode Left} type extends the {@linkcode Right} type, + * excluding `any` or `never`. + */ +export type ExtendsExcludingAnyOrNever = IsAny extends true ? IsAny : Extends; +/** + * Checks if two types are strictly equal using + * the TypeScript internal identical-to operator. + * + * @see {@link https://github.com/microsoft/TypeScript/issues/55188#issuecomment-1656328122 | much history} + */ +export type StrictEqualUsingTSInternalIdenticalToOperator = + (() => T extends (L & T) | T ? true : false) extends () => T extends (R & T) | T ? true : false + ? IsNever extends IsNever + ? true + : false + : false; +/** + * Checks that {@linkcode Left} and {@linkcode Right} extend each other. + * Not quite the same as an equality check since `any` can make it resolve + * to `true`. So should only be used when {@linkcode Left} and + * {@linkcode Right} are known to avoid `any`. + */ +export type MutuallyExtends = And<[Extends, Extends]>; +/** + * @internal + */ +declare const mismatch: unique symbol; +/** + * @internal + */ +type Mismatch = { + [mismatch]: "mismatch"; +}; +/** + * A type which should match anything passed as a value but *doesn't* + * match {@linkcode Mismatch}. It helps TypeScript select the right overload + * for {@linkcode PositiveExpectTypeOf.toEqualTypeOf | .toEqualTypeOf()} and + * {@linkcode PositiveExpectTypeOf.toMatchTypeOf | .toMatchTypeOf()}. + * + * @internal + */ +declare const avalue: unique symbol; +/** + * Represents a value that can be of various types. + */ +export type AValue = + | { + [avalue]?: undefined; + } + | string + | number + | boolean + | symbol + | bigint + | null + | undefined + | void; +/** + * Represents the type of mismatched arguments between + * the actual result and the expected result. + * + * If {@linkcode ActualResult} and {@linkcode ExpectedResult} are equivalent, + * the type resolves to an empty tuple `[]`, indicating no mismatch. + * If they are not equivalent, it resolves to a tuple containing the element + * {@linkcode Mismatch}, signifying a discrepancy between + * the expected and actual results. + */ +export type MismatchArgs = + Eq extends true ? [] : [Mismatch]; +/** + * Represents the options for the {@linkcode ExpectTypeOf} function. + */ +export interface ExpectTypeOfOptions { + positive: boolean; + branded: boolean; +} +/** + * Convert a union to an intersection. + * `A | B | C` -\> `A & B & C` + */ +export type UnionToIntersection = (Union extends any ? (distributedUnion: Union) => void : never) extends ( + mergedIntersection: infer Intersection, +) => void + ? Intersection + : never; +/** + * Get the last element of a union. + * First, converts to a union of `() => T` functions, + * then uses {@linkcode UnionToIntersection} to get the last one. + */ +export type LastOf = + UnionToIntersection Union : never> extends () => infer R ? R : never; +/** + * Intermediate type for {@linkcode UnionToTuple} which pushes the + * "last" union member to the end of a tuple, and recursively prepends + * the remainder of the union. + */ +export type TuplifyUnion> = + IsNever extends true ? [] : [...TuplifyUnion>, LastElement]; +/** + * Convert a union like `1 | 2 | 3` to a tuple like `[1, 2, 3]`. + */ +export type UnionToTuple = TuplifyUnion; +export type IsTuple = Or<[Extends, Extends]>; +export type IsUnion = Not["length"], 1>>; +/** + * A recursive version of `Pick` that selects properties from the left type that are present in the right type. + * The "leaf" types from `Left` are used - only the keys of `Right` are considered. + * + * @example + * ```ts + * const user = {email: 'a@b.com', name: 'John Doe', address: {street: '123 2nd St', city: 'New York', zip: '10001', state: 'NY', country: 'USA'}} + * + * type Result = DeepPickMatchingProps // {name: string, address: {city: string}} + * ``` + */ +export type DeepPickMatchingProps = + Left extends Record + ? Pick< + { + [K in keyof Left]: K extends keyof Right ? DeepPickMatchingProps : never; + }, + Extract + > + : Left; +export {}; diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig index 2544e94951..d5fd4778bc 100644 --- a/src/bun.js/bindings/generated_classes_list.zig +++ b/src/bun.js/bindings/generated_classes_list.zig @@ -21,6 +21,7 @@ pub const Classes = struct { pub const ExpectStringContaining = jsc.Expect.ExpectStringContaining; pub const ExpectStringMatching = jsc.Expect.ExpectStringMatching; pub const ExpectArrayContaining = jsc.Expect.ExpectArrayContaining; + pub const ExpectTypeOf = jsc.Expect.ExpectTypeOf; pub const FileSystemRouter = api.FileSystemRouter; pub const Glob = api.Glob; pub const ShellInterpreter = api.Shell.Interpreter; diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index 735e42f2c4..083a39cf8f 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -5646,6 +5646,44 @@ pub const ExpectMatcherUtils = struct { } }; +pub const ExpectTypeOf = struct { + pub const js = jsc.Codegen.JSExpectTypeOf; + pub const toJS = js.toJS; + pub const fromJS = js.fromJS; + pub const fromJSDirect = js.fromJSDirect; + + pub fn finalize( + this: *ExpectTypeOf, + ) callconv(.C) void { + VirtualMachine.get().allocator.destroy(this); + } + + pub fn create(globalThis: *JSGlobalObject) bun.JSError!JSValue { + var expect = try globalThis.bunVM().allocator.create(ExpectTypeOf); + + const value = expect.toJS(globalThis); + value.ensureStillAlive(); + return value; + } + + pub fn fnOneArgumentReturnsVoid(_: *ExpectTypeOf, _: *JSGlobalObject, _: *CallFrame) bun.JSError!JSValue { + return .js_undefined; + } + pub fn fnOneArgumentReturnsExpectTypeOf(_: *ExpectTypeOf, globalThis: *JSGlobalObject, _: *CallFrame) bun.JSError!JSValue { + return create(globalThis); + } + pub fn getReturnsExpectTypeOf(_: *ExpectTypeOf, globalThis: *JSGlobalObject) bun.JSError!JSValue { + return create(globalThis); + } + + pub fn constructor(globalThis: *JSGlobalObject, _: *CallFrame) bun.JSError!*ExpectTypeOf { + return globalThis.throw("expectTypeOf() cannot be called with new", .{}); + } + pub fn call(globalThis: *JSGlobalObject, _: *CallFrame) bun.JSError!JSValue { + return create(globalThis); + } +}; + // Extract the matcher_fn from a JSCustomExpectMatcherFunction instance inline fn getCustomMatcherFn(thisValue: JSValue, globalThis: *JSGlobalObject) ?JSValue { const matcher_fn = Bun__JSWrappingFunction__getWrappedFunction(thisValue, globalThis); diff --git a/src/bun.js/test/jest.classes.ts b/src/bun.js/test/jest.classes.ts index 57b4273aba..14939cd2fd 100644 --- a/src/bun.js/test/jest.classes.ts +++ b/src/bun.js/test/jest.classes.ts @@ -630,4 +630,158 @@ export default [ }, }, }), + define({ + name: "ExpectTypeOf", + construct: true, + call: true, + finalize: true, + JSType: "0b11101110", + values: [], + configurable: false, + klass: {}, + proto: { + toBeAny: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeUnknown: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeNever: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeFunction: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeObject: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeArray: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeNumber: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeString: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeBoolean: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeVoid: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeSymbol: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeNull: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeUndefined: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeBigInt: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeCallableWith: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toBeConstructibleWith: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + extract: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + exclude: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + pick: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + omit: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + parameter: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + parameters: { + getter: "getReturnsExpectTypeOf", + }, + constructorParameters: { + getter: "getReturnsExpectTypeOf", + }, + thisParameter: { + getter: "getReturnsExpectTypeOf", + }, + instance: { + getter: "getReturnsExpectTypeOf", + }, + returns: { + getter: "getReturnsExpectTypeOf", + }, + resolves: { + getter: "getReturnsExpectTypeOf", + }, + items: { + getter: "getReturnsExpectTypeOf", + }, + guards: { + getter: "getReturnsExpectTypeOf", + }, + asserts: { + getter: "getReturnsExpectTypeOf", + }, + toMatchObjectType: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toExtend: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toEqualTypeOf: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toMatchTypeOf: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + toHaveProperty: { + fn: "fnOneArgumentReturnsVoid", + length: 1, + }, + + map: { + fn: "fnOneArgumentReturnsExpectTypeOf", + length: 1, + }, + not: { + getter: "getReturnsExpectTypeOf", + }, + branded: { + getter: "getReturnsExpectTypeOf", + }, + }, + }), ]; diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 5ea0506a3d..e1f822b2d8 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -439,6 +439,13 @@ pub const Jest = struct { Expect.js.getConstructor(globalObject), ); + // Add expectTypeOf function + module.put( + globalObject, + ZigString.static("expectTypeOf"), + ExpectTypeOf.js.getConstructor(globalObject), + ); + createMockObjects(globalObject, module); return module; @@ -2429,6 +2436,7 @@ const Snapshots = @import("./snapshot.zig").Snapshots; const expect = @import("./expect.zig"); const Counter = expect.Counter; const Expect = expect.Expect; +const ExpectTypeOf = expect.ExpectTypeOf; const bun = @import("bun"); const ArrayIdentityContext = bun.ArrayIdentityContext; diff --git a/src/js_parser.zig b/src/js_parser.zig index a7c8601976..18b8ad94f9 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -4727,6 +4727,7 @@ pub const MacroState = struct { const Jest = struct { expect: Ref = Ref.None, + expectTypeOf: Ref = Ref.None, describe: Ref = Ref.None, @"test": Ref = Ref.None, it: Ref = Ref.None, @@ -6736,6 +6737,7 @@ fn NewParser_( p.jest.jest = try p.declareCommonJSSymbol(.unbound, "jest"); p.jest.it = try p.declareCommonJSSymbol(.unbound, "it"); p.jest.expect = try p.declareCommonJSSymbol(.unbound, "expect"); + p.jest.expectTypeOf = try p.declareCommonJSSymbol(.unbound, "expectTypeOf"); p.jest.beforeEach = try p.declareCommonJSSymbol(.unbound, "beforeEach"); p.jest.afterEach = try p.declareCommonJSSymbol(.unbound, "afterEach"); p.jest.beforeAll = try p.declareCommonJSSymbol(.unbound, "beforeAll"); diff --git a/test/integration/bun-types/fixture/test.ts b/test/integration/bun-types/fixture/test.ts index 388d3705ee..76590557a7 100644 --- a/test/integration/bun-types/fixture/test.ts +++ b/test/integration/bun-types/fixture/test.ts @@ -1,4 +1,16 @@ -import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, jest, type Mock, spyOn, test } from "bun:test"; +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + expect, + jest, + type Mock, + spyOn, + test, + expectTypeOf, +} from "bun:test"; import { expectType } from "./utilities"; const hooks = [beforeAll, beforeEach, afterAll, afterEach]; @@ -144,3 +156,10 @@ expectType(spy.mock.calls).is<[message?: any, ...optionalParams: any[]][]>(); jest.spyOn(console, "log"); jest.fn(() => 123 as const); + +test("expectTypeOf basic type checks", () => { + expectTypeOf({ name: "test" }).toMatchObjectType<{ name: string }>(); + + // @ts-expect-error + expectTypeOf({ name: 123 }).toMatchObjectType<{ name: string }>(); +}); diff --git a/test/js/bun/test/expect-type-doctest.test.ts b/test/js/bun/test/expect-type-doctest.test.ts new file mode 100644 index 0000000000..7b9fd77911 --- /dev/null +++ b/test/js/bun/test/expect-type-doctest.test.ts @@ -0,0 +1,24 @@ +import { expectTypeOf } from "bun:test"; + +// Basic type assertions +expectTypeOf().toEqualTypeOf(); +expectTypeOf(123).toBeNumber(); +expectTypeOf("hello").toBeString(); + +// Object type matching +expectTypeOf({ a: 1, b: "hello" }).toMatchObjectType<{ a: number }>(); + +// Function types +function greet(name: string): string { + return `Hello ${name}`; +} + +expectTypeOf(greet).toBeFunction(); +expectTypeOf(greet).parameters.toEqualTypeOf<[string]>(); +expectTypeOf(greet).returns.toEqualTypeOf(); + +// Array types +expectTypeOf([1, 2, 3]).items.toBeNumber(); + +// Promise types +expectTypeOf(Promise.resolve(42)).resolves.toBeNumber(); diff --git a/test/js/bun/test/expect-type-global.test.ts b/test/js/bun/test/expect-type-global.test.ts new file mode 100644 index 0000000000..497a8c6952 --- /dev/null +++ b/test/js/bun/test/expect-type-global.test.ts @@ -0,0 +1,6 @@ +test("types", () => { + expectTypeOf({ a: 1 }).toMatchObjectType<{ a: number }>(); + // @ts-expect-error + expectTypeOf({ a: 1 }).toMatchObjectType<{ a: 1 }>(); + expectTypeOf({ a: 1 as const }).toMatchObjectType<{ a: 1 }>(); +}); diff --git a/test/js/bun/test/expect-type.test.ts b/test/js/bun/test/expect-type.test.ts new file mode 100644 index 0000000000..f155e0b238 --- /dev/null +++ b/test/js/bun/test/expect-type.test.ts @@ -0,0 +1,8 @@ +import { expectTypeOf, test } from "bun:test"; + +test("types", () => { + expectTypeOf({ a: 1 }).toMatchObjectType<{ a: number }>(); + // @ts-expect-error + expectTypeOf({ a: 1 }).toMatchObjectType<{ a: 1 }>(); + expectTypeOf({ a: 1 as const }).toMatchObjectType<{ a: 1 }>(); +}); diff --git a/test/js/bun/test/jest.d.ts b/test/js/bun/test/jest.d.ts index 2d21e87e05..700f8c9679 100644 --- a/test/js/bun/test/jest.d.ts +++ b/test/js/bun/test/jest.d.ts @@ -2,6 +2,7 @@ declare var jest: typeof import("bun:test").jest; declare var describe: typeof import("bun:test").describe; declare var test: typeof import("bun:test").test; declare var expect: typeof import("bun:test").expect; +declare var expectTypeOf: typeof import("bun:test").expectTypeOf; declare var it: typeof import("bun:test").it; declare var beforeEach: typeof import("bun:test").beforeEach; declare var afterEach: typeof import("bun:test").afterEach;