Intersection of merged declarations - function types behave inconsistently
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Estancado
- Stack tecnológico
- typescript
- Área
- compilers
Línea de trabajo
Comienza ejecutando la reproducción enlazada en TypeScript Playground y compara las declaraciones combinadas de Foo y Bar con el comportamiento de las llamadas sobre uniones. Lee la discusión del issue relacionado #19064 y, después, sigue el recorrido de comprobación de tipos responsable de los tipos de función combinados y las uniones. Se considera terminado cuando el resultado de la llamada sobre la unión y ReturnType coinciden y preservan el método shuffle específico.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
🔎 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.
- Lenguaje dominante
- Go
- Estrellas
- 111k
- Forks
- 14.4k
- Merge medio
- 1 d 15 h
- PR fusionados (30 d)
- 106
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de microsoft/TypeScript
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
microsoft/TypeScript#64322 · 2 comentarios · 1 reacción · 2 asignados ·
-
Possible Improvement
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
microsoft/TypeScript#64278 · 1 comentario · 1 reacción ·
-
Docs
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
microsoft/TypeScript#64118 · 1 comentario ·
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
microsoft/TypeScript#64094 ·
-
Docs
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
microsoft/TypeScript#63959 · 5 comentarios ·
Todos los issues de microsoft/TypeScript
Issues similares
-
Type/Bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
OpenNSW/nsw-srilanka#497 ·
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
milvus-io/birdwatcher#545 ·
-
kind/bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
kubernetes-sigs/prow#953 · 1 comentario ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
caddyserver/caddy#8046 ·