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

Index type distributes over intersections too eagerly #61101

Open
Andarist opened this issue Feb 2, 2025 · 0 comments
Open

Index type distributes over intersections too eagerly #61101

Andarist opened this issue Feb 2, 2025 · 0 comments
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone

Comments

@Andarist
Copy link
Contributor

Andarist commented Feb 2, 2025

πŸ”Ž Search Terms

index keyof indexed access deferred deferral instantiation

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.8.0-dev.20250202#code/C4TwDgpgBAaghgGwK4QM4B4AqA+KBeKTAbQGsIQB7AM0IF0BuAKEYHoWpgAnOAO1SoqcAtqihVOFIVABEZEBAAmUCgCMAVhADGwKELhhpHClDhQkPAJYUejUJCgBRAB5c42hwDcIPYKgBiEkIACnAgCBRwCgCy+li4BPDIaOgA3oxQUEQA0lAWPFBy1HQAXITZtFAAZFApHOAQpTkAvkxN2Ey29Y48AI4oKADy6lrAWA5CFsDAip7eOhAu3gqitXYNUEESkJygWeRQbfg16VBsUJqcEHDTomASTiC6EMAAFhTLJxATwKVpGRnZXL5TDjSbTBSzHxEaRraS0WilAAUJ3+UDAoXCkVKA2+Y2+4MhOmqq3qjQOABoZLDsOSUVAAJT4XAeCgWBRMDItRhczr2ZxaPFgxRQBbTHjLGp1SClTYUba7faHAjIjLeHqlBy9foQIYabSCqaKGmMRl4Zms9nMBRaBBwS5iczaKz5C5XaYAZWAgggBvB2ER1qoeUmzt+n2+qDDqMBeQK5CKIPxigRUER6LCEQUpUTQoU5VN5rZHIOxYWWg1TgFzlc7i8Pn8gRCGciMTAvqN7W59NKvBAHVd1wgnu9iL+IojUf+eQHqEUSIA+r8zGAAEIgUo8JBCFQQTgHAs1Jq01HWmdz1OLyUKCgAdx4a43W53e6aB5SR5OH9Vlc0SLVb7pNUADovkmIDp0uOBZwUUc6QyJBV3XGQVDgAAvPIAHM4GkSkzleCxRFQN4kAQJRdwkTgAEI6VfDpUU0axUB0Kh8gIYDQOAcCeDPS1UTOf4AD0AH5mD49h8NEAioDUJAmJMc45UeIobxea5clEBQCLAW15CUKCoAAA3Y74uJ4gyAHJRDWOkGL4eYnDcYB3TgIQIEweoAEFUA8lQKC8JE4LRDFM2xXFAoyWoEIfKBN23XcDiqSU1lKaQIKuaDDCaRKSWlGQ0qgxRMuPVF-hheppEC41UQPFk2SORE3x5VEFkc5zXPcyAvJ8vyIFgkrl2i6QUPQngsJw05xJeKTrGgcjBFEBjOEubQEBAGj6WLD9aMYIA

πŸ’» Code

type Values<T> = T[keyof T];

// transforms from "keyed object map" to a union
type ExtractEventsFromPayloadMap<T> = Values<{
  [K in keyof T]: T[K] & { type: K };
}>;

type EnqueueObject<TEmittedEvent extends { type: PropertyKey }> = {
  // creates proxy methods
  emit: {
    [K in TEmittedEvent["type"]]: (
      payload: Omit<TEmittedEvent & { type: K }, "type">,
    ) => void;
  };
};

type Exec<TEmitted extends { type: PropertyKey }> = (
  enq: EnqueueObject<TEmitted>,
) => void;

declare function createStore<TEmitted>(definition: {
  emits: {
    [K in keyof TEmitted]: (payload: TEmitted[K]) => void;
  };
  exec: Exec<ExtractEventsFromPayloadMap<TEmitted>>;
}): any;

createStore({
  emits: {
    increased: (_: { upBy: number }) => {},
    decreased: (_: { downBy: number }) => {},
  },
  exec: (enq) => {
    enq.emit.increased({
      upBy: "bazinga", // this should error!
    });

    const fn = enq.emit.increased;
    //    ^?

    // this is just a copy of what is displayed as `enq.emit.increased`'s type
    const exactSameTypeAsAbove: (
      payload: Omit<
        { upBy: number } & { type: "increased" } & { type: "increased" },
        "type"
      >,
    ) => void = () => {};

    exactSameTypeAsAbove({
      upBy: "bazinga", // this one errors correctly
    });
  },
});

πŸ™ Actual behavior

There is no error on the annotated call

πŸ™‚ Expected behavior

It should error

Additional information about the issue

  1. keyof (T & { type: K }) gets normalized to keyof T & "type"
  2. that passed through Exclude<X, "type"> (within Omit) is left as Exclude<keyof T, "type">.
  3. then T gets instantiated with ExtractEventsFromPayloadMap<{ increased: { upBy: number; }; decreased: { downBy: number; }; }
  4. but now keyof ... returns only shared keys of this union
  5. the only shared key is type so this Exclude gets computed as never (Exclude<"type", "type">)
  6. and the final parameter type of enq.emit.increased gets computed as just {} (from { [K in never]: ... })
@RyanCavanaugh RyanCavanaugh added Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases labels Feb 4, 2025
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Feb 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Projects
None yet
Development

No branches or pull requests

2 participants