-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Treat JSON types more literally #26552
Comments
It is except where it isn't, and when it isn't, it really isn't. You wouldn't want to There are some good tools like https://quicktype.io/ that can configurably generate types from JSON; I'd recommend using something like that to "write down" the shape of the JSON you want to see. |
I'm talking specifically about raw JSON files using Typescript's native JSON typing. |
It does seem like a much deeper problem indeed, since even within the same file, even this: const string = 'text'
const object = { string } results in a
type. |
Consider if you did something like this: import customers = require("./customers.json");
// Error: "Bob Bobbily" is not assignable to "Jason Bobsworth" | "Alice Freelan" | "Jane Costo" |...
customers.push({ name: "Bob Bobbily" }); You might want to read https://blog.mariusschulz.com/2017/02/04/typescript-2-1-literal-type-widening or #20195 |
Extremely informative link, thank you. |
Is there any solution for this use case (other than casting)? sample.json {
"type": "frog"
} sample.ts import sample from './sample.json'
type AnimalType = 'frog' | 'cat' | 'dog'
type Animal = { type: AnimalType }
const a: Animal = sample // compile error What I'm trying to do is testing generated types (let's say const a = sample as Animal Is that it can mask some other "type incorrectness" in the generated types. |
@bali182 That's literally the problem I had. It seems that this option is not currently supported. type AnimalType = 'frog' | 'cat' | 'dog'
type Animal = { type: AnimalType }
const a: Animal = <%= sample_json_as_text %> for type AnimalType = 'frog' | 'cat' | 'dog'
type Animal = { type: AnimalType }
const a: Animal = {
"type": "frog"
} which would pass. |
Being bitten by this over and over again, sometimes have to resort to generating something like this from the JSON: interface _Common {
"json": { "literal": ["here"] }
}
type RecursiveReadonly<T> = T extends object
? { readonly [K in keyof T]: RecursiveReadonly<T[K]> }
: T
type Common = RecursiveReadonly<_Common>
export { Common } This types all the arrays as tuples as well, which is pretty nice. Would be much nicer though if I just had an option to import the JSON module like this. |
This do the trick :
|
@RyanCavanaugh Since we can now assert const - is there any possibility this will be re-considered in the future? Something like: import Schema from './schema.json' as const; Would be amazing. |
I'm wanting the same: ability to import a json as a const literal and get appropriate union types. My json file is a configuration, which contains a list of available app locales. I want the union type instead of just "string" Edit: created a feature request as it did not seem to exist yet: #32063 |
I'm running into exactly the same issue: need to check my test data stored in JSON files against auto-generated types from schema. Would love to see a solution for this. |
I'm not sure why this has been closed, but throwing my hat in for desiring a fix for this. Reading JSON more literally into string types would be a significant improvement to be able to put configs into JSON. As an example, the WordPress Gutenberg project is moving towards a JSON registration schema for multiple reasons. The list of available category options could and should be tightly limited to the available options. However, due to this bug, we could never enforce a proper category list which effectively breaks TS linting of the file for anyone wanting to use TS when creating Gutenberg blocks or plugins. |
I know this issue is closed but having a const json importer would be very useful. When you inline the json inside a .ts file e.g Some typescript way if going from const to strong via a typecase makes sense for those who want existing behavior. With existing json behavior any times that use discriminated unions break because type comes back as “string”. Typescript authors, how you do propose I validate json to a type? |
I've been trying to work on a fix for some of these issues here: https://github.com/pabra/json-literal-typer. If your use-case is relatively straightforward (limited special characters, no escape characters in string literals), then it may satisfy some needs. Would love to have this built-in to the language, but hopefully this will be helpful to some in the interim. |
I ran into this when one of the functions, to which I'm passing my json into into, is typed.
I get type errors saying that This defeats the purpose of the typing on I did come up with a solution, which is to not use .json and rename the file to a .ts. Then, I did a named export on the config, which I typed as the provided Here's the example:
|
Wanted to chime in here to agree with the limitations of the current implementation and provide another use case. I'm using ajv to create type guards for my types that are powered by a Type-validated-JSONschema. This is really handy because it's possible for ajv to throw type errors if the schema (and therefore the type guard) does not match the Type definition. This all works fine if defined inline:
However, I want to define my json schema in an external json file so that I can reference it in other places (e.g. in an OpenAPI spec). I cannot do this with the current TypeScript json import implementation, since this schema is not interpreted as the required string literals but as generic fooSchema.json
Foo.ts
^
|
This is a genuine challenge, especially when it comes to working with ajv schemas, but it is not a json import problem. We can trivially convert json to ts by prefixing fooSchema.ts
Foo.ts
^
What a pity we can do things with literal types within .ts files that we can't do between files. i.e. the following does successfully compile and run:
|
@Antony74 for your thing, try export default {
type: 'object',
properties: {
bar: {
type: 'integer',
},
},
required: ['bar'],
} as const You could do import { JSONSchemaType } from 'ajv'
import { Foo } from 'Foo.ts'
export default { /* ... */ } as JSONSchemaType<Foo> but I suppose that may defeat the point for you. This issue is specifically about importing |
@qm3ster Yes you're right, the (you're also right about |
@Antony74 it shouldn't assume anything, it would still conflict. If you want to typecheck but export the most literal type and not potentially partially type-erased, you could also go with const x = { /* ... */ } as const
const _: JSONSchemaType<Foo> = x
export default x |
Please consider implementing loading JSON definitions as const! This is clearly a missing feature. In our case, configuration options are loaded from a server (they usually don't change daily), so the dev runtime fetches the config and voila. However, to have better string typing, now we must convert the JSON into a fake ts file with a script. Importing JSON resources as const by default would solve this. |
Adds missing path property to struct types and removes "as unknown" casts for going from json files to ABI types. Note that the cast is still needed since ts loads JSON files with values understood as strings, so without the cast the type checker complains about `visibility` being a string rather than an `ABIVisibility`. And changing the visibility type from an enum to a union type doesn't cut it, see [this ts issue](microsoft/TypeScript#26552) for more info.
Adds missing path property to struct types and removes "as unknown" casts for going from json files to ABI types. Note that the cast is still needed since ts loads JSON files with values understood as strings, so without the cast the type checker complains about `visibility` being a string rather than an `ABIVisibility`. And changing the visibility type from an enum to a union type doesn't cut it, see [this ts issue](microsoft/TypeScript#26552) for more info.
Any update ? |
Search Terms
import json
literal type
specific type
Suggestion
When importing a JSON file, strings and numbers are typed as
string
andnumber
rather than the string or number literals in the file.Also, array literals are imported as
T[]
instead of[T1, T2, T3]
tuples.Since the JSON is almost an object literal, I believe it makes more sense to type it more specifically.
I have faced most of my issues with the former, but I believe as much information as possible should be provided, which means tuples instead of arrays.
At least the former shouldn't be particularly breaking as the types are replaced by subtypes, but of course can be breaking if
typeof
reflection is used to jam less specific types into it.Use Cases
In a number of cases, JSON imported are expected to conform to a schema that includes specific enums. Please see example.
Examples
Currently, this will not compile, because
This forces skipping the type checking of this completely statically available, and valid, object:
const typings = compile(eventSchema as any, 'Event')
Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: