Skip to content

Commit

Permalink
Use the TypeScript v5.5+ JSDoc tag @import to import types in modules.
Browse files Browse the repository at this point in the history
See:

https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/#the-jsdoc-import-tag

Note that the JSDoc type imports have to be before the real module imports to workaround this TypeScript bug where sometimes the type imports are falsely considered unused:

microsoft/TypeScript#58368 (comment)
microsoft/TypeScript#58969
  • Loading branch information
jaydenseric committed Jul 12, 2024
1 parent 8365a1e commit 38a7abc
Show file tree
Hide file tree
Showing 40 changed files with 248 additions and 170 deletions.
4 changes: 2 additions & 2 deletions CacheContext.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @ts-check

import React from "react";
/** @import Cache from "./Cache.mjs" */

/** @typedef {import("./Cache.mjs").default} Cache */
import React from "react";

/**
* [React context](https://reactjs.org/docs/context.html) for a
Expand Down
2 changes: 1 addition & 1 deletion HYDRATION_TIME_MS.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check

/** @typedef {import("./useAutoLoad.mjs").default} useAutoLoad */
/** @import useAutoLoad from "./useAutoLoad.mjs" */

/**
* Number of milliseconds after the first client render that’s considered the
Expand Down
7 changes: 4 additions & 3 deletions Loading.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// @ts-check

/** @typedef {import("./Cache.mjs").CacheKey} CacheKey */
/** @typedef {import("./Cache.mjs").CacheValue} CacheValue */
/** @typedef {import("./LoadingCacheValue.mjs").default} LoadingCacheValue */
/**
* @import { CacheKey, CacheValue } from "./Cache.mjs"
* @import LoadingCacheValue from "./LoadingCacheValue.mjs"
*/

/**
* Loading store.
Expand Down
11 changes: 6 additions & 5 deletions LoadingCacheValue.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// @ts-check

/**
* @import { CacheEventMap, CacheKey, CacheValue } from "./Cache.mjs"
* @import { LoadingEventMap } from "./Loading.mjs"
*/

import Cache from "./Cache.mjs";
import cacheEntrySet from "./cacheEntrySet.mjs";
import Loading from "./Loading.mjs";

/** @typedef {import("./Cache.mjs").CacheValue} CacheValue */
/** @typedef {import("./Cache.mjs").CacheEventMap} CacheEventMap */
/** @typedef {import("./Loading.mjs").LoadingEventMap} LoadingEventMap */

/**
* Controls loading a {@link CacheValue cache value}. It dispatches this
* sequence of events:
Expand All @@ -20,7 +21,7 @@ export default class LoadingCacheValue {
/**
* @param {Loading} loading Loading to update.
* @param {Cache} cache Cache to update.
* @param {import("./Cache.mjs").CacheKey} cacheKey Cache key.
* @param {CacheKey} cacheKey Cache key.
* @param {Promise<CacheValue>} loadingResult Resolves the loading result
* (including any loading errors) to be set as the
* {@link CacheValue cache value} if loading isn’t aborted. Shouldn’t
Expand Down
4 changes: 2 additions & 2 deletions LoadingContext.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @ts-check

import React from "react";
/** @import Loading from "./Loading.mjs" */

/** @typedef {import("./Loading.mjs").default} Loading */
import React from "react";

/**
* [React context](https://reactjs.org/docs/context.html) for a
Expand Down
10 changes: 6 additions & 4 deletions cacheDelete.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// @ts-check

/**
* @import { CacheEventMap, CacheKey } from "./Cache.mjs"
* @import { CacheKeyMatcher } from "./types.mjs"
*/

import Cache from "./Cache.mjs";
import cacheEntryDelete from "./cacheEntryDelete.mjs";

/** @typedef {import("./Cache.mjs").CacheEventMap} CacheEventMap */
/** @typedef {import("./Cache.mjs").CacheKey} CacheKey */

/**
* Deletes {@link Cache.store cache store} entries, dispatching the
* {@linkcode Cache} event {@link CacheEventMap.delete `delete`}. Useful after a
* user logs out.
* @param {Cache} cache Cache to update.
* @param {import("./types.mjs").CacheKeyMatcher} [cacheKeyMatcher] Matches
* @param {CacheKeyMatcher} [cacheKeyMatcher] Matches
* {@link CacheKey cache keys} to delete. By default all are matched.
*/
export default function cacheDelete(cache, cacheKeyMatcher) {
Expand Down
6 changes: 3 additions & 3 deletions cacheEntryDelete.mjs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// @ts-check

import Cache from "./Cache.mjs";
/** @import { CacheEventMap, CacheKey } from "./Cache.mjs" */

/** @typedef {import("./Cache.mjs").CacheEventMap} CacheEventMap */
import Cache from "./Cache.mjs";

/**
* Deletes a {@link Cache.store cache store} entry, dispatching the
* {@linkcode Cache} event {@link CacheEventMap.delete `delete`}.
* @param {Cache} cache Cache to update.
* @param {import("./Cache.mjs").CacheKey} cacheKey Cache key.
* @param {CacheKey} cacheKey Cache key.
*/
export default function cacheEntryDelete(cache, cacheKey) {
if (!(cache instanceof Cache))
Expand Down
6 changes: 3 additions & 3 deletions cacheEntryPrune.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// @ts-check

/** @import { CacheEventMap, CacheKey } from "./Cache.mjs" */

import Cache from "./Cache.mjs";
import cacheEntryDelete from "./cacheEntryDelete.mjs";

/** @typedef {import("./Cache.mjs").CacheEventMap} CacheEventMap */

/**
* Prunes a {@link Cache.store cache store} entry (if present) by dispatching
* the {@linkcode Cache} event {@link CacheEventMap.prune `prune`} and if no
* listener cancels it via `event.preventDefault()`, using
* {@linkcode cacheEntryDelete}.
* @param {Cache} cache Cache to update.
* @param {import("./Cache.mjs").CacheKey} cacheKey Cache key.
* @param {CacheKey} cacheKey Cache key.
*/
export default function cacheEntryPrune(cache, cacheKey) {
if (!(cache instanceof Cache))
Expand Down
8 changes: 4 additions & 4 deletions cacheEntrySet.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// @ts-check

import Cache from "./Cache.mjs";
/** @import { CacheEventMap, CacheKey, CacheValue } from "./Cache.mjs" */

/** @typedef {import("./Cache.mjs").CacheEventMap} CacheEventMap */
import Cache from "./Cache.mjs";

/**
* Sets a {@link Cache.store cache store} entry, dispatching the
* {@linkcode Cache} event {@link CacheEventMap.set `set`}.
* @param {Cache} cache Cache to update.
* @param {import("./Cache.mjs").CacheKey} cacheKey Cache key.
* @param {import("./Cache.mjs").CacheValue} cacheValue Cache value.
* @param {CacheKey} cacheKey Cache key.
* @param {CacheValue} cacheValue Cache value.
*/
export default function cacheEntrySet(cache, cacheKey, cacheValue) {
if (!(cache instanceof Cache))
Expand Down
6 changes: 3 additions & 3 deletions cacheEntryStale.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// @ts-check

import Cache from "./Cache.mjs";
/** @import { CacheEventMap, CacheKey } from "./Cache.mjs" */

/** @typedef {import("./Cache.mjs").CacheEventMap} CacheEventMap */
import Cache from "./Cache.mjs";

/**
* Stales a {@link Cache.store cache store} entry (throwing an error if missing)
* by dispatching the {@linkcode Cache} event
* {@link CacheEventMap.stale `stale`} to signal it should probably be reloaded.
* @param {Cache} cache Cache to update.
* @param {import("./Cache.mjs").CacheKey} cacheKey Cache key.
* @param {CacheKey} cacheKey Cache key.
*/
export default function cacheEntryStale(cache, cacheKey) {
if (!(cache instanceof Cache))
Expand Down
9 changes: 6 additions & 3 deletions cachePrune.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// @ts-check

/**
* @import { CacheKey } from "./Cache.mjs"
* @import { CacheKeyMatcher } from "./types.mjs"
*/

import Cache from "./Cache.mjs";
import cacheEntryPrune from "./cacheEntryPrune.mjs";

/** @typedef {import("./Cache.mjs").CacheKey} CacheKey */

/**
* Prunes {@link Cache.store cache store} entries by using
* {@linkcode cacheEntryPrune} for each entry. Useful after a mutation.
* @param {Cache} cache Cache to update.
* @param {import("./types.mjs").CacheKeyMatcher} [cacheKeyMatcher] Matches
* @param {CacheKeyMatcher} [cacheKeyMatcher] Matches
* {@link CacheKey cache keys} to prune. By default all are matched.
*/
export default function cachePrune(cache, cacheKeyMatcher) {
Expand Down
9 changes: 6 additions & 3 deletions cacheStale.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// @ts-check

/**
* @import { CacheKey } from "./Cache.mjs"
* @import { CacheKeyMatcher } from "./types.mjs"
*/

import Cache from "./Cache.mjs";
import cacheEntryStale from "./cacheEntryStale.mjs";

/** @typedef {import("./Cache.mjs").CacheKey} CacheKey */

/**
* Stales {@link Cache.store cache store} entries by using
* {@linkcode cacheEntryStale} for each entry. Useful after a mutation.
* @param {Cache} cache Cache to update.
* @param {import("./types.mjs").CacheKeyMatcher} [cacheKeyMatcher] Matches
* @param {CacheKeyMatcher} [cacheKeyMatcher] Matches
* {@link CacheKey cache keys} to stale. By default all are matched.
*/
export default function cacheStale(cache, cacheKeyMatcher) {
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Updated Node.js support to `^18.18.0 || ^20.9.0 || >=22.0.0`.
- Use the Node.js test runner API and remove the dev dependency [`test-director`](https://npm.im/test-director).
- Refactored tests to use the standard `AbortController`, `AbortSignal`, `Event`, `EventTarget`, `File`, `FormData`, and `Response` APIs available in modern Node.js and removed the dev dependencies [`abort-controller`](https://npm.im/abort-controller), [`event-target-shim`](https://npm.im/event-target-shim), and [`node-fetch`](https://npm.im/node-fetch).
- Use the TypeScript v5.5+ JSDoc tag `@import` to import types in modules.

### Patch

Expand Down
44 changes: 25 additions & 19 deletions fetchGraphQL.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
// @ts-check

/**
* @import { CacheValue } from "./Cache.mjs"
* @import {
* GraphQLResult,
* GraphQLResultError,
* GraphQLResultErrorLoadingFetch,
* GraphQLResultErrorResponseHttpStatus,
* GraphQLResultErrorResponseJsonParse,
* GraphQLResultErrorResponseMalformed,
* } from "./types.mjs"
*/

const ERROR_CODE_FETCH_ERROR = "FETCH_ERROR";
const ERROR_CODE_RESPONSE_HTTP_STATUS = "RESPONSE_HTTP_STATUS";
const ERROR_CODE_RESPONSE_JSON_PARSE_ERROR = "RESPONSE_JSON_PARSE_ERROR";
const ERROR_CODE_RESPONSE_MALFORMED = "RESPONSE_MALFORMED";

/** @typedef {import("./Cache.mjs").CacheValue} CacheValue */
/** @typedef {import("./types.mjs").GraphQLResult} GraphQLResult */

/**
* Fetches a GraphQL operation, always resolving a
* {@link GraphQLResult GraphQL result} suitable for use as a
Expand Down Expand Up @@ -45,7 +54,7 @@ export default function fetchGraphQL(fetchUri, fetchOptions) {

if (!response.ok)
resultErrors.push(
/** @type {import("./types.mjs").GraphQLResultErrorResponseHttpStatus} */ ({
/** @type {GraphQLResultErrorResponseHttpStatus} */ ({
message: `HTTP ${response.status} status.`,
extensions: {
client: true,
Expand All @@ -65,7 +74,7 @@ export default function fetchGraphQL(fetchUri, fetchOptions) {

if (typeof json !== "object" || !json || Array.isArray(json))
resultErrors.push(
/** @type {import("./types.mjs").GraphQLResultErrorResponseMalformed}*/ ({
/** @type {GraphQLResultErrorResponseMalformed}*/ ({
message: "Response JSON isn’t an object.",
extensions: {
client: true,
Expand All @@ -79,7 +88,7 @@ export default function fetchGraphQL(fetchUri, fetchOptions) {

if (!hasErrors && !hasData)
resultErrors.push(
/** @type {import("./types.mjs").GraphQLResultErrorResponseMalformed}*/ ({
/** @type {GraphQLResultErrorResponseMalformed}*/ ({
message:
"Response JSON is missing an `errors` or `data` property.",
extensions: {
Expand All @@ -94,7 +103,7 @@ export default function fetchGraphQL(fetchUri, fetchOptions) {
if (hasErrors)
if (!Array.isArray(json.errors))
resultErrors.push(
/** @type {import("./types.mjs").GraphQLResultErrorResponseMalformed}*/ ({
/** @type {GraphQLResultErrorResponseMalformed}*/ ({
message:
"Response JSON `errors` property isn’t an array.",
extensions: {
Expand All @@ -114,7 +123,7 @@ export default function fetchGraphQL(fetchUri, fetchOptions) {
Array.isArray(json.data)
)
resultErrors.push(
/** @type {import("./types.mjs").GraphQLResultErrorResponseMalformed}*/ ({
/** @type {GraphQLResultErrorResponseMalformed}*/ ({
message:
"Response JSON `data` property isn’t an object or null.",
extensions: {
Expand All @@ -131,7 +140,7 @@ export default function fetchGraphQL(fetchUri, fetchOptions) {
// Response JSON parse error.
({ message }) => {
resultErrors.push(
/** @type {import("./types.mjs").GraphQLResultErrorResponseJsonParse} */ ({
/** @type {GraphQLResultErrorResponseJsonParse} */ ({
message: "Response JSON parse error.",
extensions: {
client: true,
Expand All @@ -147,7 +156,7 @@ export default function fetchGraphQL(fetchUri, fetchOptions) {
// Fetch error.
({ message }) => {
resultErrors.push(
/** @type {import("./types.mjs").GraphQLResultErrorLoadingFetch} */ ({
/** @type {GraphQLResultErrorLoadingFetch} */ ({
message: "Fetch error.",
extensions: {
client: true,
Expand All @@ -166,24 +175,21 @@ export default function fetchGraphQL(fetchUri, fetchOptions) {

/**
* {@linkcode fetchGraphQL} {@link GraphQLResult GraphQL result}.
* @typedef {import("./types.mjs").GraphQLResult<
* FetchGraphQLResultError
* >} FetchGraphQLResult
* @typedef {GraphQLResult<FetchGraphQLResultError>} FetchGraphQLResult
*/

/**
* {@linkcode fetchGraphQL} {@link GraphQLResult.errors GraphQL result error}.
* @typedef {FetchGraphQLResultErrorLoading
* | import("./types.mjs").GraphQLResultError
* } FetchGraphQLResultError
* | GraphQLResultError} FetchGraphQLResultError
*/

/**
* {@linkcode fetchGraphQL} {@link GraphQLResult.errors GraphQL result error}
* that’s generated on the client, not the GraphQL server.
* @typedef {import("./types.mjs").GraphQLResultErrorLoadingFetch
* | import("./types.mjs").GraphQLResultErrorResponseHttpStatus
* | import("./types.mjs").GraphQLResultErrorResponseJsonParse
* | import("./types.mjs").GraphQLResultErrorResponseMalformed
* @typedef {GraphQLResultErrorLoadingFetch
* | GraphQLResultErrorResponseHttpStatus
* | GraphQLResultErrorResponseJsonParse
* | GraphQLResultErrorResponseMalformed
* } FetchGraphQLResultErrorLoading
*/
4 changes: 2 additions & 2 deletions fetchOptionsGraphQL.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// @ts-check

/** @import { GraphQLOperation } from "./types.mjs" */

import extractFiles from "extract-files/extractFiles.mjs";
import isExtractableFile from "extract-files/isExtractableFile.mjs";

/** @typedef {import("./types.mjs").GraphQLOperation} GraphQLOperation */

/**
* Creates default {@link RequestInit `fetch` options} for a
* {@link GraphQLOperation GraphQL operation}. If the operation contains files
Expand Down
13 changes: 8 additions & 5 deletions test/createReactTestRenderer.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// @ts-check

/**
* @import { ReactNode } from "react"
* @import { ReactTestRenderer as TestRenderer } from "react-test-renderer"
*/

import ReactTestRenderer from "react-test-renderer";

/**
* Creates a React test renderer.
* @param {import("react").ReactNode} reactRoot Root React node to render.
* @param {ReactNode} reactRoot Root React node to render.
*/
export default function createReactTestRenderer(reactRoot) {
/** @type {import("react-test-renderer").ReactTestRenderer | undefined} */
/** @type {TestRenderer | undefined} */
let testRenderer;

ReactTestRenderer.act(() => {
Expand All @@ -17,7 +22,5 @@ export default function createReactTestRenderer(reactRoot) {
);
});

return /** @type {import("react-test-renderer").ReactTestRenderer} */ (
testRenderer
);
return /** @type {TestRenderer} */ (testRenderer);
}
Loading

0 comments on commit 38a7abc

Please sign in to comment.