Skip to content
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

feat: support inferred types in conditionals #1265

Merged
merged 19 commits into from Jul 31, 2022
Merged

feat: support inferred types in conditionals #1265

merged 19 commits into from Jul 31, 2022

Conversation

daanboer
Copy link
Contributor

@daanboer daanboer commented May 28, 2022

Fixes #513, #1075

The infer keyword is used in conditional expressions to infer types of type parameters. It is the basis of many useful type constructs. This pull request implements support for inferred types, including inferred rest types.

The newly added InferType is a simple type that stores the name of the inferred parameter. Evaluation of inferred types happens in ConditionalTypeNodeParser, as type inference can only occur in conditional expressions. The heavy lifting is done by the isAssignableTo function. It has been updated to build a map of all inferred types. These inferred types are then passed to the sub-context when evaluating the true branch. Additionally, the RestType has been updated to not only support the ArrayType, but also TupleType and InferType.

See the added tests for examples.

@daanboer
Copy link
Contributor Author

daanboer commented Jun 7, 2022

@domoritz please let me know if there is anything else I need to do regarding this pull request.

@akuntsch
Copy link

akuntsch commented Jun 9, 2022

Hi @daanboer,

for me the schema generation of a recursive Partial does not work correctly.

type PrimitiveType =
    | string
    | number
    | boolean
    | undefined
    | null
    | symbol;

export type DeepPartial<T> = {
    [K in keyof T]?: T[K] extends Array<infer I>
        ? Array<DeepPartial<I>>
        : T[K] extends PrimitiveType ? T[K] : DeepPartial<T[K]>;
};

export type SchemaTestPartial = DeepPartial<{ a: string[] }>;

The generated schema for SchemaTestPartial is:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/SchemaTestPartial",
  "definitions": {
    "SchemaTestPartial": {
      "$ref": "#/definitions/DeepPartial%3Cstructure-961230428-3503-3518-961230428-3490-3519-961230428-3457-3520-961230428-0-3578%3E"
    },
    "DeepPartial<structure-961230428-3503-3518-961230428-3490-3519-961230428-3457-3520-961230428-0-3578>": {
      "type": "object",
      "properties": {
        "a": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/DeepPartial%3C%3E"
          }
        }
      },
      "additionalProperties": false
    },
    "DeepPartial<>": {
      "type": "object",
      "additionalProperties": false
    }
  }
}

The array items are now of type object instead of string.

I'm not too sure what's going wrong here but I have found that I never hit your changed code in ConditionalTypeNodeParser because the following condition is always true.

if (checkTypeParameterName == null) {
const result = isAssignableTo(extendsType, checkType);
return this.childNodeParser.createType(result ? node.trueType : node.falseType, context);
}

@daanboer
Copy link
Contributor Author

daanboer commented Jun 9, 2022

Hi @akuntsch,

Nice find! There was indeed a bug where the inferred types where not passed to the subcontext when checkTypeParameter == null. I have fixed this in the latest commit. There is however another bug that is unrelated to this pull request. A minimal reproducible example is as follows:

type MappedType<T> = {[K in keyof T]?: T[K]};
export type StringType = MappedType<string>;

Which produces:

{
  "$ref": "#/definitions/StringType",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "StringType": {
      "additionalProperties": false,
      "type": "object"
    }
  }
}

I think you can create a new issue for this bug (or check for an existing one)!

@domoritz
Copy link
Member

domoritz commented Jul 31, 2022

Thank you for the pr! Looks great.

@ccpu
Copy link
Contributor

ccpu commented Aug 7, 2022

@daanboer The inferred types feature is very useful, thanks for the PR.

However, it does not work with template literals, so I've opened an issue (#1355 ). I'd appreciate it if you could look into it if you have a chance.

@github-actions
Copy link

🚀 PR was released in v1.1.0 🚀

@github-actions github-actions bot added released This issue/pull request has been released. and removed prerelease labels Sep 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
released This issue/pull request has been released.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for inferred types
4 participants