Here's a perfect example. I maintain a simple Node library designed to connect to Apple's App Store Connect API.
https://github.com/dfabulich/node-app-store-connect-apiIt accepts, as a parameter, a URL for Apple's REST API. My library handles authentication, and returns the parsed JSON result, with a handful of tweaks to make the API more usable in JavaScript.
Depending on which URL you request, you'll get different result object back. You could get a single object in response, or an array of objects, and the type of returned objects is different for each URL type.
How would you add TypeScript types to this API? Well, Apple provides an OpenAPI documentation of all of their URLs, which I could use to autogenerate types, but then, how would I handle all of those types in response to the user's string input?
Well, it turns out that TypeScript is so amazingly fancy that you can write very clever code to parse strings at compile time, extracting parameter types etc. from string literal types. https://lihautan.com/extract-parameters-type-from-string-lit...
The documentation explains how an API like this:
app.get('/purchase/[shopid]/[itemid]/args/[...args]')
can parse its parameters into a Request type with shopid, itemid, and args[] array parameters. This would catch a bug if you had a typo, e.g. "itmid".
But the code to do that looks like this:
type IsParameter<Part> = Part extends `[${infer ParamName}]` ? ParamName : never;
type FilteredParts<Path> = Path extends `${infer PartA}/${infer PartB}`
? IsParameter<PartA> | FilteredParts<PartB>
: IsParameter<Path>;
type ParamValue<Key> = Key extends `...${infer Anything}` ? string[] : number;
type RemovePrefixDots<Key> = Key extends `...${infer Name}` ? Name : Key;
type Params<Path> = {
[Key in FilteredParts<Path> as RemovePrefixDots<Key>]: ParamValue<Key>;
};
type CallbackFn<Path> = (req: { params: Params<Path> }) => void;
function get<Path extends string>(path: Path, callback: CallbackFn<Path>) {
// TODO: implement
}
Nifty, eh? But, as the article says: how would you test this code? How would you debug it?
Clearly, I wouldn't do that. Instead, I'd write a script to autogenerate individual methods, e.g. instead of get(`apps/${appId}`) that returns a parsed JSON blob, I'd autogenerate a getApp(appId) method that returns an App object.
But that API isn't any simpler than the API I already have; it's just different.
And let's not forget that I'd have to write a script to autogenerate these methods (or just their types) based on Apple's OpenAPI specification, and now I have to maintain that code, updating my @types/node-app-store-connect-api definition every time Apple introduces a new URL you can request. Testing and debugging that is a challenge in its own right.
And even if I did it, the complexity of my library just went from a few hundred lines of glue code to 1,000+ lines of type generation (plus tests for the generated types).
This is in no way worth it for me. As a library developer, adding TypeScript types would make my life harder.