Skip to content

TypeScript ignoring checks for deeply nested computed object types #56138

Closed
@sinclairzx81

Description

@sinclairzx81

🔎 Search Terms

inference, deeply nested, no error, type evaluation, typebox, hkt

🕗 Version & Regression Information

Hi,

I've come across some unusual behavior where TypeScript seems to be skipping checks for certain kinds of computed types. This seems to be specific to deeply nested object types that are computed via intersection. I note that the language service is reporting the correct type information in editor, however the compiler seems to be skipping checks on the reported type. This behavior can be observed using the TypeBox library, specifically for object types at least 2 levels deep.

  • This is the behavior in every version I tried (5.1.6 onwards)

⏯ Playground Link

TypeScript Link Here

💻 Code

import { Static, Type } from "@sinclair/typebox"

export type Input = Static<typeof Input>
export const Input = Type.Object({
  level1: Type.Object({
    level2: Type.Object({
      foo: Type.String(),
    })
  })
})

export type Output = Static<typeof Output>
export const Output = Type.Object({
  level1: Type.Object({
    level2: Type.Object({
      foo: Type.String(),
      bar: Type.String(),
    })
  })
})

// The following functions should all report errors for the return value, however the first does not.

function problematicFunction1(ors: Input[]): Output[] {
  return ors; // <-- this does not error 
}

function problematicFunction2<T extends Output[]>(ors: Input[]): T {
  return ors; // <-- ... but this does
}

function problematicFunction3(ors: (typeof Input.static)[]): Output[] {
  return ors; // <-- ... and so does this
}

🙁 Actual behavior

First function does not report an error

🙂 Expected behavior

All functions should report errors

Additional information about the issue

I get the feeling this may have something to do with TypeBox's implementation of Static<T> and where TypeScript may be implementing some optimizations around certain forms of computed / evaluated types (but not sure). TypeBox currently implements Static<T> as follows.

type Static<T extends TSchema, P extends unknown[] = []> = (T & { params: P; })["static"]

By removing the intersection of P, TypeScript correctly asserts the problematicFunction1 return type.

type Static<T extends TSchema, P extends unknown[] = []> = T["static"] // this is fine

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions