镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Object with all context-sensitive properties requires at least one non-context-sensitive property for inference to work #64251

Description

🔎 Search Terms

object with all context-sensitive properties, self referencial types, xstate

🕗 Version & Regression Information

Tested with TypeScript 7.0.2, the issue exists even in versions as old as 4.4.4

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=6.0.3#code/PTAEAcCcHsCMBsCmBbAXKAJtRBnAdgOQAuoAlngGaKSgAioAxtJJIg0fAJ4A0j0eRRAA8SAQzwZQOIqMGhRreXk4AoBq1mIAsqIYALcogAUAbxWgyeUkVKj46AESiH3c3wHCi6E6ArRo6ACMoAC+rhbSmjjebhaiMRaJoIgCkJzoRkweIryRggCUoAC8AHygZklJWYIisZUgoAB6APx1SXmIbYkNLV0hdf0W-SH5KioNONDwAK42-OiiGJKioNM4iEg4OKB4-AC01Z5763g41qQAbogQMODURJygAAYA+uh40-DwT6BqGoI6fSGUxucjnOyOZzhdw1LzlXz+IKhaEdaLlOrxdGVZKpdKgTL8WG5GQFYplCrYmGeLoWHqtSlSEmdBl0vrQpJvHafeADNzDUYqDBseAKa5ZaSMf7aXQGPCIVBuAA89E8KQw2wpFjBNghoAA1ohONAKHQANoOVEOAC67KpInQcAAVmwiLbUQlKqaAMqWfWG41mi1MnDWq0e7EpIhpZoZQ72wNxojW4madBewqlUAXaCkDC2jkxrlfPq8oYlOpGIUUbWkeagACSQoE1k4AHlYM72MqShny9jaGMHncG02bA9FQAVMpFNwT5IiNXbcSqJLNfGgOeqiTbIwAOn3mLlV0gvdWeD1uwA7nhQGu5wqGZuF9vQE6XbeR5GW+3O0RJ2UH0pCculGJJ3kQY9B04YdGy-B4fxdf9ijcHxTQAaV9A0jRNCcw0-ZtxwndCrTKfogAOfEUiAA

💻 Code

// problem: doesn't infer D correctly, context and state are any
createMachine({
  initial: "a",
  context: { foo: 1 },
  states: {
    a: {
      entry: (context, state) => {
        context
        // ^? any
        state
        // ^? any
      }
    }
  }
})

// solution: add a useless non-context-sensitive property `_: null` 
createMachine({
  initial: "a",
  context: { foo: 1 },
  states: {
    a: {
      entry: (context, state) => {
        context
        // ^? { foo: number }
        state
        // ^? "a"
      },
      _: null
    }
  }
})

declare const createMachine:
  <D extends {
    initial: keyof D["states"],
    context: object,
    states: {
      [S in keyof D["states"]]: {
        entry?: (context: D["context"], state: S) => void,
        _?: null
      }
    }
  }>
    (definition: IdentityObject<D>) =>
      D

type Identity<T> =
  T extends any
    ? ( T extends (...a: never) => unknown ? T :
        T extends object ? IdentityObject<T> :
        T
      )
    : never

type IdentityObject<T> =
  { [K in keyof T]: Identity<T[K]> }

🙁 Actual behavior

The first createMachine invocation doesn't infer the type parameter correctly (it requires at least one non-context-sensitive property) and hence context and state parameters of entry are not inferred.

🙂 Expected behavior

The first createMachine invocation should infer the type parameter correctly without having to pass in a non-context-sensitive property leading to inference of context and state parameters of entry

Additional information about the issue

The premise is adding (or rather not adding) an extra useless property shouldn't make a difference to the inference

Activity

RyanCavanaugh commented on Sep 14, 2026

@RyanCavanaugh
Member

Mateusz Burzyński (@Andarist) any thoughts (on this or the PR) ?

RyanCavanaugh commented on Sep 14, 2026

@RyanCavanaugh
Member

Copilot cites #48798 as prior work in this area, with #54029 as a superset of the linked PR

Andarist commented on Sep 16, 2026

@Andarist
Contributor

#54029 would resolve this issue already here - so it's kinda strong duplicate of #48798 . That said... #54029 doesn't resolve all cases and I'm cooking up a revised PR of that for TS Go. Stay tuned 😉

devanshj commented on Sep 17, 2026

@devanshj
Author

Mateusz Burzyński (@Andarist) Nice... A bit of a trivia / fyi given you took this problem out of txstate (linking for others), this whole Identity (or InferNarrowest) is actually a workaround... so even if this reverse mapped type issue is resolved, it's still not enough to type abstractions like xstate, for that we need #64091, eg I'd be curious if you can type this with your PR... But then again any progress is good!

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

    Possible ImprovementThe current behavior isn't wrong, but it's possible to see that it might be better in some cases

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions