Skip to content

Regression: 7.0.1-RC Unable to Satisfy Recursive Mapped Type Constraint #63568

@sinclairzx81

Description

@sinclairzx81

🔎 Search Terms

Mapped Types, Satisfying Constraints, Recursive Type Mapping, TypeScript 7, RC

🕗 Version & Regression Information

This changed between versions

Between 6.0.3 and 7.0.1-rc

This changed in commit or PR

Unknown. However I recall things were working ok approximately 2 weeks ago. The update may be recent.

  • This is the behavior in every version I tried

Tested 4.9.5 through to 6.0.3. Problem is specific to 7.0.1-rc

⏯ Playground Link

https://www.typescriptlang.org/play/?target=99&module=7&ts=4.9.5#code/JYWwDg9gTgLgBALzgMyhEcDkCIBNMBQBA9MXALSVXU2130ONMlkCSAdqgIYDOMUAVwDGMAVACmLCkxmy58ouIAekWHBgBPMOLgAVAMpCAFuJBc4AXjgBvdVvEAuOHyjB2AczgBfRSujxNbT0AeTAYYAh2LgAbAB5dezhlGHF2XB49QxMzS0zjUy4APlyEoIAyGywAPwgwiKjozCd+AR0fAmVVeDcUqGQuIR1dACVxZFjR5CSlFLSMlzd3YuTU9Lzs81sCODttJ0xJzAAaOG24CWQnSdOfTv84HvE+gaH9fkXp2bWDfJytncCjiwb1cHkwN18XV2QwACmhtLBgOIMlZRkJoLhYnDak9NABpcQaE4-DaFSH3R7PQYhABGACtxCIsfDcUiMis5npsQjwsjljNVhkSQUbGdAftgvTGTBCDswCzEcinNzWciCO1SNJ5NqddqpABZLhgMCLKS680WhgEQFwABaeFKOisCAAdOiJC79OhxI6iDbdAAxNAgSaxADCkRSM0+gq5Ct5PBO1w5awWHmKVgAFGdkwLOQBrQkQKYR9hRmBnHYAfj0QfQjvDkeSJ1L5YA2pMALpknY7Jyu+24ABy4gAbk8CABKa2JQPBlWwDSNsvJGOc3QLhPExIpoVZApHM4AdWAMCMjrXa0HF6sc-r9mX5e32kKh52J7PoXCkRil4y18SW8dzzb4v3qX8awHPAwJ-OIP3PexiiceDHUPDM4HgmCGj9Wc6xASUGSZVtV13OMcUVRM4E3Nk-zInk2TfOBNUNY1xFwPRElGdwJB4Hh6jgAAJJ5JB2Ugzk1YJ8ycHYADYXQABhdABmcSyADLhgGiJwAHYFJdABGcgoCEVTVLgABRKA0CgJwL0wWw2wJDQHnYOBCw0YsqPjNlO2VbzkUcwlO1osyQjqWD4n3MxihrQcsJieI8IbYiZhOaiAqc7tijgF1ctynNkQEaJ4FIgCgmdF04qlJlrErOBAuctw3KLKZ0p4Xza3neMlxSmA0v8ngGu7M4vDJdDRh4IqKxnII7xAEEPgqwcFo8HDZqSh9etojcBufHRSOFaLcmzHYLwOgjpViNxkCeLzyITba2pizr0Auoim1Su76L5OAHDOM6QKFUNrtu3Mvnmd50zgGs5tDXqkzGJD-uA8HMkhzwYbwlbPD+nYoOHMcJ2nM1LVJ0mpAAVR4Lh3EkTUyYZ801p0DgwAEeBbzemBYlqnYlFs0NMAAQUwV8zg0AWxliYXRcYhBJfGGWyVGmadGCdm2Y5l6QAbWxe01G11ZgTXcnxrmebOIXbOx3tbbtu3NT5-tKrwbGAG51ROVn2ey+2-YdsgdglxAXdwd26v9yP-cdxBneW9GPajpPo7ILwTldd1xBdAASBYwDJIA

💻 Code

The following code will fault on 7.0.1-rc

The issue relates to the TFromObject mapping where it's not possible to satisfy the left side ZodType constraint. The issue is specific to resolving a foreign TRef<T> on a remote Context object.

import z from 'zod'

// ------------------------------------------------------------------
// Infrastructure
// ------------------------------------------------------------------

export type TSchema = { type: string }

export type TOptional<Type extends TSchema = TSchema> = Type & { '~optional': true }

export interface TRef<Ref extends string> extends TSchema { 
  type: 'Ref', 
  ref: Ref 
}
export interface TString extends TSchema { 
  type: 'String' 
}

export type TProperties = Record<PropertyKey, TSchema>

export interface TObject<Properties extends TProperties> extends TSchema {
  type: 'Object'
  properties: Properties
}

// ------------------------------------------------------------------
// Mapping
// ------------------------------------------------------------------
type ZodType = z.core.SomeType

type TFromRef<Context extends TProperties, Ref extends string> = (
  Ref extends keyof Context
    ? TFromType<Context, Context[Ref]>
    : z.ZodNever
)
type TFromProperty<Context extends TProperties, Type extends TSchema,
  WithType extends ZodType = TFromType<Context, Type>,
  WithOptional extends ZodType = Type extends TOptional ? z.ZodOptional<WithType> : WithType,
> = WithOptional

type TFromObject<Context extends TProperties, Properties extends TProperties,
  // Mapped Type Regression Here
  //
  // Ok:   6.0.3
  // Fail: 7.0.1-rc
  //
  // Error: Type '{ [Key in keyof Properties]: Properties[Key] extends 
  //  TOptional<TSchema> ? ZodOptional<TFromType<Context, Properties[Key]>>  .....
  Result extends ZodType = z.ZodObject<{
    [Key in keyof Properties]: TFromProperty<Context, Properties[Key]>
  }>
> = Result

type TFromString = z.ZodString

type TFromType<Context extends TProperties, Type extends TSchema> = (
  Type extends TObject<infer Properties extends TProperties> ? TFromObject<Context, Properties> :
  Type extends TRef<infer Ref extends string> ? TFromRef<Context, Ref> :
  Type extends TString ? TFromString :
  z.ZodNever
)

// ------------------------------------------------------------------
// Usage
// ------------------------------------------------------------------

type Input = TObject<{
  x: TRef<'A'>,
  y: TRef<'A'>,
  z: TRef<'A'>
}>
type Output = TFromType<{    // type Output = z.ZodObject<{
  A: TString                 //   x: z.ZodString;
}, Input>                    //   y: z.ZodString;
                             //   z: z.ZodString;
                             // }, z.core.$strip>

🙁 Actual behavior

Expected similar behavior to TypeScript 6

🙂 Expected behavior

Expected similar behavior to TypeScript 6

Additional information about the issue

I note that by commenting the conditional TRef<T> arm on TFromType<T> will make the problem disappear. So the issue appears specific to how TypeScript 7 is resolving for the foreign type. Previous versions of the compiler did seem to collapse to the target type, where as TypeScript 7 seems to keep the type expansive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions