Intersection of merged declarations - function types behave inconsistently
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 35/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Ferma
- Stack tecnologico
- typescript
- Ambito
- compilers
Direzione di ricerca
Inizia eseguendo la riproduzione collegata in TypeScript Playground e confronta le dichiarazioni unite di Foo e Bar con il comportamento delle chiamate sulle union. Leggi la discussione dell’issue correlata #19064, quindi traccia il percorso del controllo dei tipi responsabile dei tipi di funzione uniti e delle union. Il lavoro è completato quando il risultato della chiamata sulla union e ReturnType concordano e preservano il metodo shuffle specifico.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
🔎 Search Terms
declaration merging
🕗 Version & Regression Information
- This is a type inference problem
- This problem appears in Typescript 3.3.3, 3.5.1, 3.9.7, 4.9.5, 5.3.3 and 5.4.0-dev.20240207
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about declaration merging
⏯ Playground Link
💻 Code
type MyArrayExtension<T> = Array<T> & { shuffle(): void }
interface Foo { getList(): Array<string> }
interface Foo { getList(): MyArrayExtension<string> }
interface Bar { getList(): Array<string> }
interface Bar { getList(): MyArrayExtension<string> }
type FooListType = ReturnType<Foo["getList"]> // as expected: string[] & {shuffle(): void;}
type BarListType = ReturnType<Bar["getList"]> // as expected: string[] & {shuffle(): void;}
type FarListType = ReturnType<(Foo|Bar)["getList"]> // as expected: string[] & {shuffle(): void;}
let fooFn = ({} as Foo).getList; // { (): Array<string>; (): MyArrayExtension<string>; }
let barFn = ({} as Bar).getList; // { (): Array<string>; (): MyArrayExtension<string>; }
let farFn = ({} as Foo|Bar).getList; // { (): Array<string>; (): MyArrayExtension<string>; } | { (): Array<string>; (): MyArrayExtension<string>; }
let farList: FarListType = farFn(); // should work, but error:
/*
Type 'string[]' is not assignable to type 'MyArrayExtension<string>'.
Property 'shuffle' is missing in type 'string[]' but required in type '{ shuffle(): void; }'.(2322)
*/
({} as Foo).getList().shuffle(); // works
({} as Bar).getList().shuffle(); // works
({} as Foo|Bar).getList().shuffle(); // Error: Property 'shuffle' does not exist on type 'string[]'.(2339)
🙁 Actual behavior
There are two interfaces (Foo and Bar), that each are constituted of two merged declarations.
Each interface individually behaves such that the later declaration wins (getList(): MyArrayExtension<string> in either case). When changing the order (define the MyArrayExtension returning interfaces first), the return type accordingly is string[].
However, when intersecting Foo|Bar, the behaviour becomes inconsistent:
ReturnType<(Foo|Bar)["getList"]>is what I would expect (compatible withMyArrayExtension<string>), but({} as Foo|Bar).getList()is not assignable to a variable of this type
🙂 Expected behavior
My use case is the following: I have an external dependency that defines interfaces with functions that return T[].
Since I know those functions return a specific type that extends T[], I want to augment the module (using declare module) and give the functions a more specific return type.
The behaviour for non-intersected types if perfect for this. The later (e.g. provided by my declare module augmentation) wins.
However, it breaks down when intersecting two types from the external dependency, as described above.
I would expect type inference to work consistently. I think it's good to be able to override/make types more specific this way, and I think this ability should not be lost when intersecting types for which this has been done.
Additional information about the issue
@jcalz explained to me on StackOverflow that this problem is not restricted to module augmentation, but appears even when merging declarations in the same file. The problem is probably related to #19064.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.4k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
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.
Altre issue di microsoft/TypeScript
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
microsoft/TypeScript#64322 · 2 commenti · 1 reazione · 2 assegnatari ·
-
Possible Improvement
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
microsoft/TypeScript#64278 · 1 commento · 1 reazione ·
-
Docs
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
microsoft/TypeScript#64118 · 1 commento ·
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
microsoft/TypeScript#64094 ·
-
Docs
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
microsoft/TypeScript#63959 · 5 commenti ·
Tutte le issue di microsoft/TypeScript
Issue simili
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 92/100
milvus-io/birdwatcher#545 ·
-
kind/bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
kubernetes-sigs/prow#953 · 1 commento ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
caddyserver/caddy#8046 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
jaegertracing/jaeger#9588 ·