microsoft / microsoft/TypeScript
Type Inference Fails with Generic Types
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.4k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
Descrizione
🔎 Search Terms
error recursive generic types
🕗 Version & Regression Information
- This changed between versions v5.7.0-beta and v4.1.5
⏯ Playground Link
💻 Code
type BaseItem<T = any> = { id: T }
interface Snapshot<T extends BaseItem<I> = BaseItem, I = any> {
id: string,
time: number,
collectionName: string,
items: T[],
}
const selector: FlatQuery<Snapshot<BaseItem>> = { collectionName: 'asdf' }
// ^^
// No error ✅
function test<ItemType extends BaseItem<IdType>, IdType = any>() {
type ItemKeys = DotNotationKeys<Snapshot<ItemType, IdType>>
// ^^
// "id" | "time" | "collectionName" | "items" | `items.${string}`
type CollectionNameType = Flatten<Get<Snapshot<ItemType, IdType>, 'collectionName'>>
// ^^
// "string"
const genericSelector: FlatQuery<Snapshot<ItemType, IdType>> = { collectionName: 'asdf' }
// ^^
// Error ❌: Type '{ collectionName: string; }' is not assignable to type 'FlatQuery<Snapshot<ItemType, IdType>>'.
}
// Utility type to check if a type is an array or object.
type IsObject<T> = T extends object ? (T extends Array<any> ? false : true) : false
// Recursive type to generate dot-notation keys
type DotNotationKeys<T> = {
[K in keyof T & (string | number)]:
T[K] extends Array<infer U>
// If it's an array, include both the index and the $ wildcard
? `${K}` | `${K}.$` | `${K}.${DotNotationKeys<U>}`
// If it's an object, recurse into it
: IsObject<T[K]> extends true
? `${K}` | `${K}.${DotNotationKeys<T[K]>}`
: `${K}` // Base case: Just return the key
}[keyof T & (string | number)]
type Split<S extends string, Delimiter extends string> =
S extends `${infer Head}${Delimiter}${infer Tail}`
? [Head, ...Split<Tail, Delimiter>]
: [S]
type GetTypeByParts<T, Parts extends readonly string[]> =
Parts extends [infer Head, ...infer Tail]
? Head extends keyof T
? GetTypeByParts<T[Head], Extract<Tail, string[]>>
: Head extends '$'
? T extends Array<infer U>
? GetTypeByParts<U, Extract<Tail, string[]>>
: never
: never
: T
type Get<T, Path extends string> =
GetTypeByParts<T, Split<Path, '.'>>
type Flatten<T> = T extends any[] ? T[0] : T
type FlatQuery<T> = {
[P in DotNotationKeys<T>]?: Flatten<Get<T, P>>
}
🙁 Actual behavior
Typescript isn't able to assign { collectionName: 'asdf' } when using generic types:
function test<ItemType extends BaseItem<IdType>, IdType = any>() {
const selector: FlatQuery<Snapshot<ItemType, IdType>> = { collectionName: 'asdf' }
// ^^
// Type '{ collectionName: string; }' is not assignable to type 'FlatQuery<Snapshot<ItemType, IdType>>'.
}
Without generic types it work seamlessly:
const selector: FlatQuery<Snapshot<BaseItem>> = { collectionName: 'asdf' }
🙂 Expected behavior
{ collectionName: 'asdf' } should be successfully assignable to FlatQuery<Snapshot<ItemType, IdType>> using generic types.
Additional information about the issue
Related issue: https://github.com/maxnowack/signaldb/pull/1030
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia con il TypeScript Playground collegato e riduci l’esempio generico ricorsivo che coinvolge BaseItem, Snapshot, Get e FlatQuery, confrontandolo con l’assegnazione non generica. Il lavoro è completato quando l’assegnazione generica { collectionName: 'asdf' } viene accettata senza indebolire il comportamento atteso riportato.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript
- Ambito
- compilers
- Tipo di issue
- Bug
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Ferma
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 30/100