microsoft / microsoft/TypeScript

Index type distributes over intersections too eagerly

未关闭
#61,101 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

Domain: Indexed Access Types Help Wanted Possible Improvement
主要语言
Go
星标
111k
派生
14.3k
平均合并
2 天 4 小时
30 天内合并 PR
132

描述

🔎 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]: ... })

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从链接的 TypeScript Playground 复现开始,跟踪 indexed access、keyof、intersections 和 Omit 的 checker 路径。将带注解的 callback 调用与等价的显式函数类型进行比较。完成的标准是:推断出的 enq.emit.increased 调用会拒绝将字符串传给 upBy,并且有一个覆盖所报告案例的回归测试。

由索引模型根据 Issue 内容生成。

评估

技术栈
typescript
领域
compilers
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
42/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。