`keyof T['prop']` becomes never when the object contains a context-sensitive function

未关闭
#55,039 5 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
35/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
停滞
技术栈
typescript
领域
compilers

调研方向

从链接的 TypeScript Playground 开始,复现递归的 Type<TAcceptedKeys, TType> 示例。比较 triggerFn 没有参数和有参数时推断出的类型与诊断结果,尤其关注 keys 和 shouldBeKeyofTType。完成标准是函数参数不再意外改变最终的 keyof 类型。

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

描述

Bug Domain: Indexed Access Types Help Wanted

Bug Report

🔎 Search Terms

Not sure how to put this but:

  • recursive type
  • function
  • parameter
  • generics
🕗 Version & Regression Information

Tested on these versions:

  • typescript@5.1.3
  • typescript@5.2.0-dev.20230716 dev
⏯ Playground Link

Playground Link

Code
type Type<
  TAcceptedKeys extends string,
  TType extends Type<TAcceptedKeys>=any
> = {
  /**
   * We're using the keys of this property, that is why
   * we use a recursive type.
   */
  obj?: Record<TAcceptedKeys, 1>
  /**
   * Just for the sake of illustration. 
   * In the circumstances of the bug this will be never[].
   */
  keys: (keyof TType['obj'])[]
  /**
   * A function with a parameter inside the recursive type.
   * This triggers the bug.
   */
  triggerFn?: (param: number) => void
  /**
   * This will always be TType, regardless of whether
   * a parameter is declared in `triggerFn` or not.
   */
  shouldBeTType?: TType
  /**
   * This will be `keyof TType` as expected if a parameter
   * is not declared in triggerFn, but it will turn to `undefined`
   * as soon as a parameter is declared in that function.
   *
   * If the below property is passed to defineType
   * the type will be as expected:
   * triggerFn: () => {}
   *
   * However this will trigger the bug:
   * triggerFn: (param) => {}
   */
  shouldBeKeyofTType?: keyof TType
}

const defineType = <TAcceptedKeys extends string>() =>
  <const TType extends Type<TAcceptedKeys, TType>>(type: TType) => type

defineType<'apple' | 'banana'>()({
  obj: {
    apple: 1,
    banana: 1
  },
  keys: [
    'apple'
  ],

  /**
   * Toggle these comments to see how the bug works.
   */
  triggerFn: () => {},      // won't produce diagnostics
  // triggerFn: (param) => {}, // type 'string' is not assignable to type 'never'

  /**
   * Toggle these comments to see diagnostics information.
   */
  // shouldBeTType: null,
  // shouldBeKeyofTType: null
})
🙁 Actual behavior

The presence or absence of a parameter in an object member function has effect on this object type in certain circumstances.

🙂 Expected behavior

It shouldn't.

主要语言
Go
星标
111k
派生
14.4k
平均合并
1 天 19 小时
30 天内合并 PR
117

贡献指南

打开贡献指南

从这里开始

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

microsoft/TypeScript 的其他 Issue

查看 microsoft/TypeScript 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

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