-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Support overriding the types of a set of JSON files #49703
Comments
A few extra comments:
In our codebase, we have several thousand locstring files, and that many more imports of them, so explicitly casting each import would be considered cumbersome. |
I don't see any immediate blocker here. @weswigham any concerns with making ambient module declarations apply to json extensions? I would have expected this to work already
This would be a pretty big architectural lift from our end; I'd really rather not. This seems like a place where some pre-build tooling would be appropriate depending on the scenario. |
Yeah, I don't know why it doesn't already - probably some weird prioritization logic for json modules.
Definitely. It's what we do here - generate declarations from loc json. It's probably worth noting that even if ambient pattern declarations don't currently apply to |
TypeScript infers the JSON types, this behavior is really painful, because sometime JSON files are use as "database-like" code. for example:
Iooking for something feature disable the JSON type infer:
|
JSON files can now have types provided for them by an adjacent |
Sorry to dig up an old issue, but out of curiosity, is the intent of Happy to open an issue + repro for this to demonstrate. |
You want |
Thanks! I gave that a try, but TS couldn't seem to find the type declarations for the
I enabled
To clarify, importing a Anything else I should try? I feel like I am missing something. |
I imagine |
Suggestion
π Search Terms
JSON declare module change type resolveJsonModule
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
Allow applications to override/declare the imported type of a set of JSON modules.
We seem to be able to declare types of imported modules with
declare module
, but if the target module ends with .json extension, the declaration does not seem to take effect. For example, this works, with some limitations:But this does not work (just because of the .json extension):
π Motivating Example
This feature would allow developers to, at compiler time, use branded string types to identify strings that were loaded from specific JSON files, as opposed to plain strings. The compiler could then detect if functions that expect such branded strings are called with other types of strings.
π» Use Cases
Our application stores strings for localization in *.locstring.json files.
For example,
hello.locstring.json
might contain:Code consumes these strings by importing the locstring file and calling a
loc(resourceId: string): string
function. For example:We're using resolveJsonModule, so the
strings
variable is properly typed and the compiler will detect if you try to access a field that does not exist, likestrings.helloWorld
. The type ofstrings.hello
comes asstring
as one would expect from a normal .json file.This presents a problem - while it is valid to call
loc
withstrings.hello
as parameter, it should be invalid to callloc
with"Hello World"
, for example. When multiple functions and parameters are involved, people accidentally end up calling things that look likeloc(loc(strings.hello))
and that does not work, becauseloc
expects the parameters to be 'resource ID' (ie, fields from the locstring files), and not any plain string.The reason for this is that in debug mode,
loc
is pretty much a pass-through, so it outputs the "localized" string as found in the JSON file. But in retail there is a lookup involved. At build time, the contents of all *locstring.json files are processed and the string we get back fromstrings.hello
ends up being a unique identifier, let's say"a2w"
or something like that. When the application runs, it will load the actual set of strings and put them into a map, and thenloc
will take the given resourceId passed as parameter and lookup the corresponding string in the current language.In this scenario, passing a random plain string to
loc
as a parameter is a bug, since it will not exist on the map - or worse, the random string is user input (like a file name) and it just happens to match one of the resource ID and it would be localized to a random string, so that can't happen.Ideally, we want to detect invalid calls to
loc
at compile time.We could use a branded string type to limit the types of strings one can pass to
loc
, for example:Doing so causes every call to
loc(string.someId)
to be flagged as an error, because the compiler rightfully believesstring cannot be assigned to ResourceId
.Trying to tell the compiler that the fields it gets from the *.locstring.json files are in fact ResourceId does not seem to work:
On the other hand, IF the files were named just .locstring (without the .json extension) then it kinda works, although we lose one thing in the process:
For us, renaming the files at this point is not feasible because there are several devops processes around them.
The other issue is that, IF the
declare module "*.locstring.json"
were to work as expected, with that particular definition we would be losing the detection of incorrect field names. That comes from writing simplyvalue: { [key: string]: ResourceId }
in the declaration. I'm not sure there's a way to refer to the original type of the JSON.Bonus points:
Our locstring files can contain multiple strings, and every localizable string must also contain a comment for localization to know how to properly deal with it, with the name derived from the original name. For example, a login.locstring.json file would look like this:
Ideally only
strings.nameLabel
andstrings.passwordLabel
would be validResourceId
to be passed toloc
.That being said, it is not that big of a deal if the "_id.comment" fields also come up as ResourceId because using them is cumbersome and people don't make that mistake.
So, the two requests in this issue are:
declare module "*.some_extension.json"
to override the type produced by a plain .json file?The text was updated successfully, but these errors were encountered: