microsoft / microsoft/TypeScript
Assigning a callable return type of a generic function directly to some generic parameter results in error
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Go
- Estrellas
- 111k
- Forks
- 14.3k
- Merge medio
- 1 d 19 h
- PR fusionados (30 d)
- 117
Descripción
TypeScript Version: above 3.3.3
Code
To see the actual behavior depending on a version of TS it is better to open the code below in the playground
type Callable<T> = { (t: T): any; };
declare function utilA<T>(
callable: Callable<T>,
fn: (t: T) => any
): any
declare function utilB<T>(
callable: Callable<T>,
params: {
fn: (t: T) => any
}
): any
declare function utilC<T>(
params: {
callable: Callable<T>,
fn: (t: T) => any
}
): any
/**
* Case 1: directly assigning a callable
*/
declare const callable: Callable<number>
utilA(
callable,
t => t.toExponential() // t is a number, OK
)
utilB(
callable,
{
fn: t => t.toExponential() // t is a number, OK
}
)
utilC({
callable,
fn: t => t.toExponential() // t is a number, OK
})
/**
* Case 2: directly assigning the result of a function returning a callable
*/
declare function computeCallableA(): Callable<number>
utilA(
computeCallableA(),
t => t.toExponential() // t is a number, OK
)
utilB(
computeCallableA(),
{
fn: t => t.toExponential() // t is a number, OK
}
)
utilC({
callable: computeCallableA(),
fn: t => t.toExponential() // t is a number, OK
})
/**
* Case 3: directly assigning the result of a generic function returning a callable
*/
declare function computeCallableB<T>(t: T): Callable<T>
utilA(
computeCallableB(100),
t => t.toExponential() // t is a number, OK
)
utilB(
computeCallableB(100),
{
fn: t => t.toExponential() // t is a number, OK
}
)
utilC({
callable: computeCallableB(100), // Error
fn: t => t.toExponential() // t is an unknown
})
/**
* The last case is strange IMO. The result type of `computeCallableB` is immediately known.
*
* Hovering the last `utilC` shows the following:
*
* function utilC<number>(params: {
* callable: Callable<number>;
* fn: (t: number) => any;
* }): any
*
* Despite the fact that TS infers generic `T` of `utilC`, assignment to `callable` param
* gives: "Type 'Callable<number>' is not assignable to type 'Callable<unknown>'.".
*
* It is hard to understand whats going on. More than that, everything works in TS v3.3.3.
* In newer versions the behavior is broken.
*
* This has an impact on the library I help to maintain. Such use cases are not rare and
* people are forced to assign the result of `computeCallableB(100)` to a variable first,
* and then to a `callable` parameter, which affects DX:
*/
const computeCallableBResult = computeCallableB(100)
utilC({
callable: computeCallableBResult, // This works!
fn: t => t.toExponential() // t is a number, OK
})
Expected behavior:
The invocation of
utilC({
callable: computeCallableB(100), // Error
fn: t => t.toExponential() // t is an unknown
})
gives no errors.
Actual behavior:
Strange behavior in versions above 3.3.3.
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.
Línea de trabajo
Comienza abriendo la reproducción enlazada de TypeScript Playground y compara las llamadas de Case 3 con los casos que funcionan y con el comportamiento en TypeScript 3.3.3. Investiga la inferencia genérica para el objeto en línea utilC cuando callable recibe computeCallableB(100). Se considera terminado cuando la llamada en línea no produce errores e infiere t como number, sin requerir una variable intermedia.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- typescript
- Área
- compilers
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Estancado
- Claridad
- Bastante claro
- Aptitud para principiantes
- 42/100