Skip to content

Fix TS errors #1580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/unlucky-pumpkins-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-fetch": patch
---

Fix type errors
2 changes: 1 addition & 1 deletion packages/openapi-fetch/examples/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
"react-dom": "18.2.0"
},
"devDependencies": {
"@types/node": "20.11.19",
"@types/node": "20.11.24",
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7",
"openapi-typescript": "workspace:^",
2 changes: 1 addition & 1 deletion packages/openapi-fetch/package.json
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@
"openapi-typescript-fetch": "^1.1.3",
"superagent": "^8.1.2",
"typescript": "^5.3.3",
"vitest": "^1.2.2",
"vitest": "^1.3.1",
"vitest-fetch-mock": "^0.2.2"
}
}
31 changes: 19 additions & 12 deletions packages/openapi-fetch/src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type {
ErrorResponse,
SuccessResponse,
FilterKeys,
HasRequiredKeys,
HttpMethod,
MediaType,
OperationRequestBodyContent,
PathsWithMethod,
ResponseObjectMap,
OperationRequestBodyContent,
HasRequiredKeys,
SuccessResponse,
} from "openapi-typescript-helpers";

// Note: though "any" is considered bad practice in general, this library relies
@@ -80,7 +81,7 @@ type BodyType<T = unknown> = {
stream: Response["body"];
};
export type ParseAs = keyof BodyType;
export type ParseAsResponse<T, O extends FetchOptions> = O extends {
export type ParseAsResponse<T, O> = O extends {
parseAs: ParseAs;
}
? BodyType<T>[O["parseAs"]]
@@ -110,13 +111,7 @@ export type RequestBodyOption<T> =
export type FetchOptions<T> = RequestOptions<T> &
Omit<RequestInit, "body" | "headers">;

/** This type helper makes the 2nd function param required if params/requestBody are required; otherwise, optional */
export type MaybeOptionalInit<P extends {}, M extends keyof P> =
HasRequiredKeys<FetchOptions<FilterKeys<P, M>>> extends never
? [(FetchOptions<FilterKeys<P, M>> | undefined)?]
: [FetchOptions<FilterKeys<P, M>>];

export type FetchResponse<T, O extends FetchOptions> =
export type FetchResponse<T, O> =
| {
data: ParseAsResponse<
FilterKeys<SuccessResponse<ResponseObjectMap<T>>, MediaType>,
@@ -174,7 +169,19 @@ export interface Middleware {
onResponse?: typeof onResponse;
}

export type ClientMethod<Paths extends {}, M> = <
/** This type helper makes the 2nd function param required if params/requestBody are required; otherwise, optional */
export type MaybeOptionalInit<
P extends Record<HttpMethod, {}>,
M extends keyof P,
> =
HasRequiredKeys<FetchOptions<FilterKeys<P, M>>> extends never
? [(FetchOptions<FilterKeys<P, M>> | undefined)?]
: [FetchOptions<FilterKeys<P, M>>];

export type ClientMethod<
Paths extends Record<string, Record<HttpMethod, {}>>,
M extends HttpMethod,
> = <
P extends PathsWithMethod<Paths, M>,
I extends MaybeOptionalInit<Paths[P], M>,
>(
1 change: 0 additions & 1 deletion packages/openapi-fetch/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
// @ts-expect-error
import createFetchMock from "vitest-fetch-mock";
import createClient, {
1 change: 0 additions & 1 deletion packages/openapi-fetch/test/v7-beta.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
// @ts-expect-error
import createFetchMock from "vitest-fetch-mock";
import createClient, {
4 changes: 2 additions & 2 deletions packages/openapi-fetch/tsconfig.json
Original file line number Diff line number Diff line change
@@ -9,11 +9,11 @@
"moduleResolution": "NodeNext",
"noUncheckedIndexedAccess": true,
"outDir": "dist",
"skipLibCheck": true,
"skipLibCheck": false,
"strict": true,
"target": "ESNext",
"types": ["vitest/globals"]
},
"include": ["src", "test"],
"exclude": ["node_modules"]
"exclude": ["examples", "node_modules"]
}
18 changes: 10 additions & 8 deletions packages/openapi-typescript-helpers/index.d.ts
Original file line number Diff line number Diff line change
@@ -58,14 +58,15 @@ export type OperationRequestBodyMediaContent<T> =
? FilterKeys<NonNullable<OperationRequestBody<T>>, "content"> | undefined
: FilterKeys<OperationRequestBody<T>, "content">;
/** Return first `content` from a Request Object Mapping, allowing any media type */
export type OperationRequestBodyContent<T> = FilterKeys<
OperationRequestBodyMediaContent<T>,
MediaType
> extends never
?
| FilterKeys<NonNullable<OperationRequestBodyMediaContent<T>>, MediaType>
| undefined
: FilterKeys<OperationRequestBodyMediaContent<T>, MediaType>;
export type OperationRequestBodyContent<T> =
FilterKeys<OperationRequestBodyMediaContent<T>, MediaType> extends never
?
| FilterKeys<
NonNullable<OperationRequestBodyMediaContent<T>>,
MediaType
>
| undefined
: FilterKeys<OperationRequestBodyMediaContent<T>, MediaType>;
/** Return first 2XX response from a Response Object Map */
export type SuccessResponse<T> = ResponseContent<FilterKeys<T, OkStatus>>;
/** Return first 5XX or 4XX response (in that order) from a Response Object Map */
@@ -97,4 +98,5 @@ export type FindRequiredKeys<T, K extends keyof T> = K extends unknown
? never
: K
: K;
/** Does this object contain required keys? */
export type HasRequiredKeys<T> = FindRequiredKeys<T, keyof T>;
10 changes: 5 additions & 5 deletions packages/openapi-typescript/package.json
Original file line number Diff line number Diff line change
@@ -62,21 +62,21 @@
"typescript": "^5.x"
},
"dependencies": {
"@redocly/openapi-core": "^1.9.0",
"@redocly/openapi-core": "^1.10.3",
"ansi-colors": "^4.1.3",
"supports-color": "^9.4.0",
"yargs-parser": "^21.1.1"
},
"devDependencies": {
"@types/degit": "^2.8.6",
"@types/js-yaml": "^4.0.9",
"@types/node": "^20.11.19",
"@types/node": "^20.11.24",
"degit": "^2.8.4",
"del-cli": "^5.1.0",
"esbuild": "^0.20.0",
"esbuild": "^0.20.1",
"execa": "^7.2.0",
"typescript": "^5.3.3",
"vite-node": "^1.2.2",
"vitest": "^1.2.2"
"vite-node": "^1.3.1",
"vitest": "^1.3.1"
}
}
3 changes: 2 additions & 1 deletion packages/openapi-typescript/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { fileURLToPath } from "node:url";
import { beforeAll, describe, expect, test, vi } from "vitest";
import openapiTS, { astToString } from "../src/index.js";
import type { OpenAPI3, OpenAPITSOptions } from "../src/types.js";
import type { TestCase } from "./test-helpers.js";
@@ -692,7 +693,7 @@ export type operations = Record<string, never>;`,
);
}

it("does not mutate original reference", async () => {
test("does not mutate original reference", async () => {
const schema: OpenAPI3 = {
openapi: "3.1",
info: { title: "test", version: "1.0" },
56 changes: 28 additions & 28 deletions packages/openapi-typescript/test/lib/ts.test.ts
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ import {
} from "../../src/lib/ts.js";

describe("addJSDocComment", () => {
it("single-line comment", () => {
test("single-line comment", () => {
const property = ts.factory.createPropertySignature(
undefined,
"comment",
@@ -30,7 +30,7 @@ describe("addJSDocComment", () => {
}`);
});

it("multi-line comment", () => {
test("multi-line comment", () => {
const property = ts.factory.createPropertySignature(
undefined,
"comment",
@@ -57,7 +57,7 @@ describe("addJSDocComment", () => {
}`);
});

it("escapes internal comments", () => {
test("escapes internal comments", () => {
const property = ts.factory.createPropertySignature(
undefined,
"comment",
@@ -77,19 +77,19 @@ describe("addJSDocComment", () => {
});

describe("oapiRef", () => {
it("single part", () => {
test("single part", () => {
expect(astToString(oapiRef("#/components")).trim()).toBe(`components`);
});

it("multiple parts", () => {
test("multiple parts", () => {
expect(astToString(oapiRef("#/components/schemas/User")).trim()).toBe(
`components["schemas"]["User"]`,
);
});
});

describe("tsEnum", () => {
it("string members", () => {
test("string members", () => {
expect(astToString(tsEnum("-my-color-", ["green", "red", "blue"])).trim())
.toBe(`enum MyColor {
green = "green",
@@ -98,7 +98,7 @@ describe("tsEnum", () => {
}`);
});

it("name from path", () => {
test("name from path", () => {
expect(
astToString(
tsEnum("#/paths/url/get/parameters/query/status", [
@@ -112,7 +112,7 @@ describe("tsEnum", () => {
}`);
});

it("string members with numeric prefix", () => {
test("string members with numeric prefix", () => {
expect(astToString(tsEnum("/my/enum/", ["0a", "1b", "2c"])).trim())
.toBe(`enum MyEnum {
Value0a = "0a",
@@ -121,7 +121,7 @@ describe("tsEnum", () => {
}`);
});

it("number members", () => {
test("number members", () => {
expect(astToString(tsEnum(".Error.code.", [100, 101, 102])).trim())
.toBe(`enum ErrorCode {
Value100 = 100,
@@ -130,7 +130,7 @@ describe("tsEnum", () => {
}`);
});

it("number members with x-enum-descriptions", () => {
test("number members with x-enum-descriptions", () => {
expect(
astToString(
tsEnum(
@@ -153,7 +153,7 @@ describe("tsEnum", () => {
}`);
});

it("x-enum-varnames", () => {
test("x-enum-varnames", () => {
expect(
astToString(
tsEnum(
@@ -173,7 +173,7 @@ describe("tsEnum", () => {
}`);
});

it("x-enum-varnames with numeric prefix", () => {
test("x-enum-varnames with numeric prefix", () => {
expect(
astToString(
tsEnum(
@@ -189,7 +189,7 @@ describe("tsEnum", () => {
}`);
});

it("partial x-enum-varnames and x-enum-descriptions", () => {
test("partial x-enum-varnames and x-enum-descriptions", () => {
expect(
astToString(
tsEnum(
@@ -209,7 +209,7 @@ describe("tsEnum", () => {
}`);
});

it("x-enum-descriptions with x-enum-varnames", () => {
test("x-enum-descriptions with x-enum-varnames", () => {
expect(
astToString(
tsEnum(
@@ -237,15 +237,15 @@ describe("tsEnum", () => {
});

describe("tsPropertyIndex", () => {
it("numbers -> number literals", () => {
test("numbers -> number literals", () => {
expect(astToString(tsPropertyIndex(200)).trim()).toBe(`200`);
expect(astToString(tsPropertyIndex(200.5)).trim()).toBe(`200.5`);
expect(astToString(tsPropertyIndex(Infinity)).trim()).toBe(`Infinity`);
expect(astToString(tsPropertyIndex(NaN)).trim()).toBe(`NaN`);
expect(astToString(tsPropertyIndex(10e3)).trim()).toBe(`10000`);
});

it("valid strings -> identifiers", () => {
test("valid strings -> identifiers", () => {
expect(astToString(tsPropertyIndex("identifier")).trim()).toBe(
`identifier`,
);
@@ -257,7 +257,7 @@ describe("tsPropertyIndex", () => {
expect(astToString(tsPropertyIndex("10e3")).trim()).toBe(`"10e3"`);
});

it("invalid strings -> string literals", () => {
test("invalid strings -> string literals", () => {
expect(astToString(tsPropertyIndex("kebab-case")).trim()).toBe(
`"kebab-case"`,
);
@@ -273,27 +273,27 @@ describe("tsPropertyIndex", () => {
});

describe("tsIsPrimitive", () => {
it("null", () => {
test("null", () => {
expect(tsIsPrimitive(NULL)).toBe(true);
});

it("number", () => {
test("number", () => {
expect(tsIsPrimitive(NUMBER)).toBe(true);
});

it("string", () => {
test("string", () => {
expect(tsIsPrimitive(STRING)).toBe(true);
});

it("boolean", () => {
test("boolean", () => {
expect(tsIsPrimitive(BOOLEAN)).toBe(true);
});

it("array", () => {
test("array", () => {
expect(tsIsPrimitive(ts.factory.createArrayTypeNode(STRING))).toBe(false);
});

it("object", () => {
test("object", () => {
expect(
tsIsPrimitive(
ts.factory.createTypeLiteralNode([
@@ -310,29 +310,29 @@ describe("tsIsPrimitive", () => {
});

describe("tsUnion", () => {
it("none", () => {
test("none", () => {
expect(astToString(tsUnion([])).trim()).toBe(`never`);
});

it("one", () => {
test("one", () => {
expect(astToString(tsUnion([STRING])).trim()).toBe(`string`);
});

it("multiple (primitive)", () => {
test("multiple (primitive)", () => {
expect(
astToString(tsUnion([STRING, STRING, NUMBER, NULL, NUMBER, NULL])).trim(),
).toBe(`string | number | null`);
});

it("multiple (const)", () => {
test("multiple (const)", () => {
expect(
astToString(
tsUnion([NULL, tsLiteral("red"), tsLiteral(42), tsLiteral(false)]),
).trim(),
).toBe(`null | "red" | 42 | false`);
});

it("multiple (object types)", () => {
test("multiple (object types)", () => {
const obj = ts.factory.createTypeLiteralNode([
ts.factory.createPropertySignature(undefined, "foo", undefined, STRING),
]);
Original file line number Diff line number Diff line change
@@ -227,17 +227,32 @@ responses: {
given: {
parameters: [
{ in: "path", name: "user_id", schema: { type: "string" } },
{ in: "path", name: "user_id_deprecated", schema: { type: "string", deprecated: true } },
{
in: "path",
name: "user_id_deprecated",
schema: { type: "string", deprecated: true },
},
{ in: "query", name: "search", schema: { type: "string" } },
{ in: "query", name: "search_deprecated", schema: { type: "string", deprecated: true } },
{
in: "query",
name: "search_deprecated",
schema: { type: "string", deprecated: true },
},
],
responses: {
"200": {
description: "OK",
content: { "application/json": { schema: { type: "object", properties: {
hello: { type: "string" },
hello_deprecated: { type: "string", deprecated: true }
}}}},
content: {
"application/json": {
schema: {
type: "object",
properties: {
hello: { type: "string" },
hello_deprecated: { type: "string", deprecated: true },
},
},
},
},
},
},
},
2 changes: 1 addition & 1 deletion packages/openapi-typescript/test/yaml.test.ts
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ const cwd = os.platform() === "win32" ? fileURLToPath(root) : root; // execa bug
const cmd = "./bin/cli.js";

describe("YAML features", () => {
it("merge", async () => {
test("merge", async () => {
const result = await execa(cmd, ["./test/fixtures/yaml-merge.yaml"], {
cwd,
});
1 change: 1 addition & 0 deletions packages/openapi-typescript/tsconfig.json
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"sourceRoot": ".",
"outDir": "dist",
"types": ["vitest/globals"]
494 changes: 293 additions & 201 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@
"module": "NodeNext",
"moduleResolution": "NodeNext",
"removeComments": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "ESNext",