Skip to content

[Feature] Use JSON Schema to determine imported JSON type when availableΒ #49314

Closed

Description

Suggestion

πŸ” Search Terms

json schema

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

Currently when importing JSON the types provided is basically just the inferred type treated the JSON as an object literal.

It would however be helpful to support JSON schema declared types to create types that may be either be more narrow or less narrow that more accurately reflect what one can expect with the JSON.

πŸ“ƒ Motivating Example

Consider as one example the following JSON:

// mime-map.json
{
    "mimeTypes": {
        "js": "text/javascript",
        "mjs": "text/javascript",
        "cjs": "application/node",
        "json": "application/json"
    }
}

When we import it, we are unable to use this as a general record object despite that being the intention of the value:

import mimeMap from "./mime-map.json" assert { "type": "json" };

const extension: string = getExtensionSomehow();
// Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ js: string; mjs: string; cjs: string; json: string; }'.
const mimeType = mimeMap.mimeTypes[extension];

if (mimeType === undefined) {
    // ...Unrecognized file type
} else {
    // ...do something with the type
}

This happens because the inferred type is too narrow, now there's no way that TS could know this directly, however JSON schema is an existing mechanism for declaring such types.

For example if I were to define the schema:

// mime-map.schema.json
{
    "$schema": "http://json-schema.org/schema",
    "type": "object",
    "properties": {
        "mimeTypes": {
            "type": "object",
            "additionalProperties": {
                "type": "string"
            }
        }
    }
}

This would effectively declare a JSON object of type:

{
    mimeTypes: Record<string, string>
}

Existing tooling already has support for such schemas, for example VSCode can already recognize incorrect types in a file which such a schema:

Screenshot from 2022-05-31 06-42-18

It would be nice if TS could also recognize JSON schema types, and generate appropriate TS types for them so that types when imported correspond more appropriately.

πŸ’» Use Cases

The core use case is that JSON types would more accurately represented by TS recognizing a JSON Schemas, this would allow the JSON file to evolve more so with TS still being able to receive correct type information about the contents rather than just a best guess based on the object shapes.

Notes

This is a potentially breaking change for existing JSON imports, however in most cases people would probably want the JSON Schema they are using. If there was significant breakage an opt-in might be neccessary e.g. useJSONSchema in tsconfig or similar.

Activity

  1. changed the title [-][Feature] Use JSON schema to determine JSON type when available[/-] [+][Feature] Use JSON Schema to determine JSON type when available[/+] on May 30, 2022
  2. changed the title [-][Feature] Use JSON Schema to determine JSON type when available[/-] [+][Feature] Use JSON Schema to determine imported JSON type when available[/+] on May 30, 2022
  3. MartinJohns commented on May 31, 2022

    @MartinJohns
    Contributor

    Related: #32063

    Personally I don't really like this suggestion. JSON Schema is just too... weird. And support for it would just be half-baked. Many features can't be represented in TypeScript types (e.g. oneOf and not, or propertyNames.pattern and additionalProperties). With some other features it's fairly unclear how TypeScript should behave, for example default: What type should TypeScript use here? The default value is not inserted in the absence of a value, so having an optional property makes most sense and the type provided for the value in default is dropped entirely. Fun fact: The value for default does not have to validate against the schema, you can say the property stores a string, but the default is the number 123.

  4. fatcerberus commented on May 31, 2022

    @fatcerberus

    Fun fact: The value for default does not have to validate against the schema, you can say the property stores a string, but the default is the number 123.

    😱
    I'm... quite scared right now.

  5. MartinJohns commented on May 31, 2022

    @MartinJohns
    Contributor

    It's mentioned here: https://json-schema.org/understanding-json-schema/reference/generic.html

    The default keyword specifies a default value. This value is not used to fill in missing values during the validation process. Non-validation tools such as documentation generators or form generators may use this value to give hints to users about how to use a value. However, default is typically used to express that if a value is missing, then the value is semantically the same as if the value was present with the default value. The value of default should validate against the schema in which it resides, but that isn’t required.

    That being said, the value in my example would not be 123, but it would still be undefined (as the default is not inserted). But according to JSON Schema this undefined should be treated as if it were the value 123.

    I'd also expect some library / tools to wrongly insert the default value in absence of the property.

  6. RyanCavanaugh commented on May 31, 2022

    @RyanCavanaugh
    Member

    The Venn diagram of things supported by JSON Schema and by TypeScript has substantial area in both non-overlapping regions, including things we're likely to not ever implement (maxProperties, minLength, etc). Without a 1:1 translation between JSON Schema and TS we'd be left making a ton of policy decisions that people might need to be configurable, and it'd just be a huge mess. But this can be done out-of-band by any tool (such tools already exist) according to the particular project's need without any significant damage to the overall scenario.

  7. Jamesernator commented on Feb 27, 2023

    @Jamesernator
    Author

    I'm gonna close this in favour of a more direct TypeScript typings oriented approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Out of ScopeThis idea sits outside of the TypeScript language design constraintsSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions