Skip to content

Instantly share code, notes, and snippets.

@jonathantneal
Created August 23, 2022 01:14
Show Gist options
  • Save jonathantneal/a9b9eaf6889038cf5d9841aedaba99ca to your computer and use it in GitHub Desktop.
Save jonathantneal/a9b9eaf6889038cf5d9841aedaba99ca to your computer and use it in GitHub Desktop.
Fetch JSON returns the result with narrow typing
// @ts-check
import * as fs from 'node:fs'
/** Fetches JSON returns the result with narrow typing. */
export let fetchJSON = /** @type {(input: RequestInfo | URL, init?: RequestInit) => any} */ (
async (/** @type {string} */ input, config = any) => {
const response = await fetch(input, config)
const responseJSON = await response.json()
typedHash[input] = JSON.stringify(responseJSON)
setTyping()
return responseJSON
}
)
/** Path to the typing for this script. */
const typedPath = new URL('./fetchJSON.d.ts', import.meta.url)
/** Text used to populate the typing for this script. */
const typedText = `type JFetch<T> = (\n\tPromise<any>\n)\n\nexport declare function fetchJSON<T extends string>(resource: T): JFetch<T>`
/** Hashmap used to store typing results. */
const typedHash = /** @type {Record<string, string>} */ (Object.create(null))
/** Updates the typing file. */
const setTyping = () => fs.writeFileSync(typedPath, typedText.slice(0, 20) + Object.entries(typedHash).reduce(
(list, [ input, responseJSON ]) => list + `T extends "${input}" ? Promise<${responseJSON}> :\n\t`,
''
) + typedText.slice(20))
const any = /** @type {any} */ (null)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment