microsoft / microsoft/TypeScript
"Lookup" Type Broken When Using Generics
还没有人认领这个 Issue。
- 主要语言
- Go
- 星标
- 111k
- 派生
- 14.3k
- 平均合并
- 2 天 4 小时
- 30 天内合并 PR
- 132
描述
### 🔎 Search Terms
"nested lookup with generic", "type lookup with generic"
### 🕗 Version & Regression Information
- For `doesNotWork1`, this changed between versions `3.9.7` and `4.0.5`.
- For other "not working" examples, this is the behavior in every version I tried, and I reviewed the FAQ for entries about generics within lookup tables.
### ⏯ Playground Link
https://www.typescriptlang.org/play/?ts=5.9.3#code/JYOwLgpgTgZghgYwgAgOrDACwMIHsC2+uIyA3gFDJXIzAQA2AJgIwBcyIArvgEbQDclarQaMATOwDOYKKADmggL7lyoSLEQp0WAMoAHCAmBx6yCAA9IIRpLQYcBIiQrVkkg0ZPsuvAeWWq4NDwSMj6hsb0ADK4uADWnHpkQlTuEV52uh6RSipqwZrIeITEMfGJZpYQ1rbhntGxCUku1AiOxOzaDiUgueRgAJ4GyGVNADwAcnD4KBZWNshxEAO4MEXtIKOJAHzIALzJrgDaANLIoIvLq+s9W3pHUzMAuk8A-OzFTncP0xBPp08lIJyAB6EHICYAeQAKgBRdhYYC2JHIHhQeLVMwAN0xAHd7MgAAZLFZrT6lRqJQnIQAoBJcBkS0vVqZg4LYwLhUSg2oRqpBGMhcJwwDRcFBKtM9PQUFg4CLGJyQLgRbixXFkBy3BBZlB0VBbFAIGBOFAQOQYJwQAgwMBiG4CBBHhAxmc5tUFiTrnVIndtgAKACU7CxuGAApaVDaIGkyFVUDikjYI0pejGAHImZE07sDhHXDQ6Ewk8wADQpfMiJgSZBpnlONNl-PUTMZMQABgAzI3qIpga4ozG4wnq3d03XiNn9ocmwXREmAKzdpuV8TsDMOxEgOQN8uuMHINq6wxgegM2g1DWskWI2wrtyYIVMDjKrmX6AQXfN7IZDtiJfIXsVD3cELA8MA5VtEgUVlEVCUtRgIHPCBGGpSQH04J8+GQEx6FwXFkOQRhOBlTk9HRAwoEGDUhggWw0Lw+RLzlc4RXojCBT4ct9yhOEEUwFEACpcTZATYzVRiLixDsADoAE5pIAdnLAd5VwWiJmVVA1STUcThzacm33P0yNwCjBgDNxv3od4bi+FMASOAAiFt6Ecp5kAAH2QeDENAAi6UkTlmPwUBgHwbhLxRNjMJQQ1AvoHENU5ODrF8kBkNQ0BQkJdKcXFLyfKQlDkDi3AEtopKiUKvyUOkurP1SKz2Gq9LGH-VwVyTFrkPa4RC1XbzUqK-9AK4kDzDAiC7Wgq9ItsVV2NfOAeGlSrD0Na1T3OBDwGAGAz365ESHHEgYDFObLIiWgEC1EVrhJSQxohGF4QuhUKqVFU1XOEg4BABk8skSDsKxOBgHoZbVouKU4AGOR0Xg5TiBjd7JA0sAtPjEcUxdfS81cFz2GYNs2wAFhGoDqH3UDjymqD2Vmm8xMWrDIZIg8xQ2k8GTDPk9oO0Qjo5npYwJHCJXwKVaKenjXqZ1Hny++Mfuw-7kEB4G4FB8G2ZVmG4YR6wkejVT1M0tUO3YXS8Ya2ciyJxdbZXas0z+5VMGgNNy2UZQgA
### 💻 Code
```ts
interface WithCommon {
field1: number;
field2: string;
}
interface WithSpecial extends WithCommon {
special: number;
}
interface SpecialLookup {
special: WithSpecial;
}
interface CommonLookup extends SpecialLookup {
common: WithCommon;
}
type Lookup = {
[K in keyof CommonLookup[Name]]?: CommonLookup[Name][K];
};
// NOTE: this is broken even with `keyof CommonLookup` — key `special` has to be removed to see current error return since with `CommonLookup` we do detect that `special` is not a shared key of all members
function someName(): void {
const works1: Lookup<'special'> = {
field1: 1,
field2: 'common',
special: 203,
};
const works2: Lookup<'common'> = {
field1: 5,
field2: 'something',
// correctly finds that this field should not be there
special: 32,
};
// expectation is that `undefined` should be allowed due to property types showing that it should be
// NOTE: this *was* working in v3.9.7
const doesNotWork1: Lookup = {
// (property) special?: CommonLookup[K]["special"] | undefined — so at minimum this should be resolve to `undefined` since `never | undefined` resolves to `undefined`...
special: undefined,
field1: undefined,
field2: undefined,
};
// expectation is that this would be able to correctly identify fields in common for this specific set of keys
// NOTE: this does not work in any version available in playground
const doesNotWork2: Lookup = {
special: 1004,
}
// expectation is that this would be able to correctly identify fields in common with all examples
// NOTE: this does not work in any version available in playground
const doesNotWork3: Lookup = {
field1: 15,
field2: 'another'
}
}
```
### 🙁 Actual behavior
When using a generic as the input to a "lookup" type, we should be able to correctly type the common fields of the "looked-up" interfaces.
What is interesting here is that we appear to get correct behavior from "code completion" (i.e. `special` is correctly typed as a property of `Lookup` with type `CommonLookup[K]["special"] | undefined`), but actually setting the presented type value doesn't work.
### 🙂 Expected behavior
We should get correct typing for the generic `Lookup` type:
- `doesNotWork1` should allow `undefined` as a value since field type evaluates to `CommonLookup[K][Field] | undefined`.
- `doesNotWork2` should allow `number` as value for field `special` since all interfaces within `keyof SpecialLookup` have `special: number` on the interface.
- `doesNotWork3` should allow values for `field1` and `field2` for the same reason as `doesNotWork2`.
### Additional information about the issue
As I called out in my `NOTE` within the code example, this is also broken in a "simpler" example where the generic is `K extends keyof CommonLookup`. I presented the above code example because it is the most similar to my use case and I wasn't sure if fixing the "simpler" case would also fix the one where we are choosing a smaller key set.
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
从链接的 TypeScript Playground 开始,在所注明的编译器版本中重现 doesNotWork1–3 示例。跟踪泛型查找的类型检查行为,然后验证预期的 undefined 和公共字段赋值能够通过类型检查,同时不允许无效字段。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- typescript
- 领域
- compilers
- Issue 类型
- 缺陷
- 难度
- 5/5
- 预计耗时
- 一周以上
- 活跃度
- 停滞
- 描述清晰度
- 描述清楚
- 新手友好度
- 35/100