From faf68ae59f34616320d26a178726165521459dd2 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Wed, 14 Jun 2023 15:27:32 +0100 Subject: [PATCH] Refactored tests and fixed #6 --- package.json | 1 + pnpm-lock.yaml | 63 ++++++++++++++++++ src/types.ts | 4 +- tests/fromAny.test.ts | 41 ++++++++++++ tests/fromExact.test.ts | 26 ++++++++ tests/{utils.test.ts => fromPartial.test.ts} | 67 +++----------------- tests/test-utils.ts | 2 + 7 files changed, 143 insertions(+), 61 deletions(-) create mode 100644 tests/fromAny.test.ts create mode 100644 tests/fromExact.test.ts rename tests/{utils.test.ts => fromPartial.test.ts} (50%) diff --git a/package.json b/package.json index fcd3ac9..d9d27e8 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "devDependencies": { "@changesets/cli": "^2.26.0", "@types/node": "^18.14.5", + "axios": "^1.4.0", "tsup": "^6.6.3", "turbo": "^1.8.3", "typescript": "^4.9.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f780f1..d6f61ca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,6 +3,7 @@ lockfileVersion: 5.4 specifiers: '@changesets/cli': ^2.26.0 '@types/node': ^18.14.5 + axios: ^1.4.0 tsup: ^6.6.3 turbo: ^1.8.3 typescript: ^4.9.5 @@ -11,6 +12,7 @@ specifiers: devDependencies: '@changesets/cli': 2.26.0 '@types/node': 18.14.5 + axios: 1.4.0 tsup: 6.6.3_typescript@4.9.5 turbo: 1.8.3 typescript: 4.9.5 @@ -827,11 +829,25 @@ packages: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true + /asynckit/0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: true + /available-typed-arrays/1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} dev: true + /axios/1.4.0: + resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: true + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -1013,6 +1029,13 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /combined-stream/1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: true + /commander/4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1107,6 +1130,11 @@ packages: object-keys: 1.1.1 dev: true + /delayed-stream/1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: true + /detect-indent/6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -1363,12 +1391,31 @@ packages: pkg-dir: 4.2.0 dev: true + /follow-redirects/1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: true + /for-each/0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 dev: true + /form-data/4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + /fs-extra/7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -1914,6 +1961,18 @@ packages: picomatch: 2.3.1 dev: true + /mime-db/1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: true + + /mime-types/2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + /mimic-fn/2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -2216,6 +2275,10 @@ packages: react-is: 17.0.2 dev: true + /proxy-from-env/1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: true + /pseudomap/1.0.2: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} dev: true diff --git a/src/types.ts b/src/types.ts index a332441..d65a533 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,8 +3,8 @@ export type NoInfer = [T][T extends any ? 0 : never]; /** * Adapted from type-fest's PartialDeep */ -export type PartialDeep = T extends (...args: any[]) => unknown - ? T | undefined +export type PartialDeep = T extends (...args: any[]) => any + ? Partial | undefined : T extends object ? T extends ReadonlyArray // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156 ? ItemType[] extends T // Test for arrays (non-tuples) specifically diff --git a/tests/fromAny.test.ts b/tests/fromAny.test.ts new file mode 100644 index 0000000..188a161 --- /dev/null +++ b/tests/fromAny.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from "vitest"; +import { Equal, Expect, accept } from "./test-utils"; +import { fromAny } from "../src"; + +describe("fromAny", () => { + it("Should return whatever you pass in", () => { + const result = fromAny({ foo: "bar" }); + + expect(result).toEqual({ foo: "bar" }); + }); + + it("Should return unknown if not called in a function's args", () => { + const result = fromAny({ foo: "bar" }); + + type test = Expect>; + }); + + it("Should let you pass anything to a function", () => { + accept<{ foo: string; bar: number }>(fromAny("str")); + + accept<{ foo: string; bar: number }>(fromAny(124123)); + + accept<{ foo: string; bar: number }>( + fromAny({ + foo: "awdaw", + }), + ); + }); + + it("When passed into a function, it should NOT give excess property warnings", () => { + accept<{ + foo: string; + bar: number; + }>( + fromAny({ + foo: "bar", + baz: 1, + }), + ); + }); +}); diff --git a/tests/fromExact.test.ts b/tests/fromExact.test.ts new file mode 100644 index 0000000..81a6e3c --- /dev/null +++ b/tests/fromExact.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from "vitest"; +import { fromAny, fromExact, fromPartial } from "../src"; +import { Equal, Expect, accept } from "./test-utils"; + +describe("fromExact", () => { + it("Should return whatever you pass in", () => { + const result = fromExact({ foo: "bar" }); + + expect(result).toEqual({ foo: "bar" }); + }); + + it("Should return the type you pass in", () => { + const result = fromExact({ foo: "bar" }); + + type test = Expect>; + }); + + it("When passed to a function, it should expect the exact type", () => { + accept<{ foo: string; bar: number }>( + // @ts-expect-error + fromExact({ + foo: "bar", + }), + ); + }); +}); diff --git a/tests/utils.test.ts b/tests/fromPartial.test.ts similarity index 50% rename from tests/utils.test.ts rename to tests/fromPartial.test.ts index 1ed28fd..d50d979 100644 --- a/tests/utils.test.ts +++ b/tests/fromPartial.test.ts @@ -1,8 +1,7 @@ import { describe, expect, it } from "vitest"; -import { fromAny, fromExact, fromPartial } from "../src"; -import { Equal, Expect } from "./test-utils"; - -const accept = (_t: T) => {}; +import { fromPartial } from "../src"; +import { Equal, Expect, accept } from "./test-utils"; +import { AxiosInstance } from "axios"; describe("fromPartial", () => { it("Should return whatever you pass in", () => { @@ -67,65 +66,15 @@ describe("fromPartial", () => { }), ); }); -}); - -describe("fromAny", () => { - it("Should return whatever you pass in", () => { - const result = fromAny({ foo: "bar" }); - - expect(result).toEqual({ foo: "bar" }); - }); - - it("Should return unknown if not called in a function's args", () => { - const result = fromAny({ foo: "bar" }); - - type test = Expect>; - }); - - it("Should let you pass anything to a function", () => { - accept<{ foo: string; bar: number }>(fromAny("str")); - accept<{ foo: string; bar: number }>(fromAny(124123)); - - accept<{ foo: string; bar: number }>( - fromAny({ - foo: "awdaw", - }), - ); + it("Should accept functions", () => { + accept<() => void>(fromPartial({})); }); - it("When passed into a function, it should NOT give excess property warnings", () => { + it("Should accept interfaces which combine object properties and a call signature", () => { accept<{ + (): void; foo: string; - bar: number; - }>( - fromAny({ - foo: "bar", - baz: 1, - }), - ); - }); -}); - -describe("fromExact", () => { - it("Should return whatever you pass in", () => { - const result = fromExact({ foo: "bar" }); - - expect(result).toEqual({ foo: "bar" }); - }); - - it("Should return the type you pass in", () => { - const result = fromExact({ foo: "bar" }); - - type test = Expect>; - }); - - it("When passed to a function, it should expect the exact type", () => { - accept<{ foo: string; bar: number }>( - // @ts-expect-error - fromExact({ - foo: "bar", - }), - ); + }>(fromPartial({})); }); }); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index d2f5f6d..9d5d9e0 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -37,3 +37,5 @@ export type UnionToIntersection = ( : never; export const doNotExecute = (func: () => any) => {}; + +export const accept = (_t: T) => {};