microsoft / microsoft/TypeScript
Assigning a callable return type of a generic function directly to some generic parameter results in error
Personne n'a encore pris cette issue.
- Langage dominant
- Go
- Étoiles
- 111k
- Forks
- 14.4k
- Merge moyen
- 1 j 19 h
- PR mergées (30 j)
- 117
Description
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.
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par ouvrir la reproduction liée dans TypeScript Playground et comparez les appels de Case 3 avec les cas fonctionnels et le comportement dans TypeScript 3.3.3. Étudiez l’inférence générique pour l’objet inline utilC lorsque callable reçoit computeCallableB(100). Le travail est terminé lorsque l’appel inline ne produit aucune erreur et infère t comme étant de type number, sans nécessiter de variable intermédiaire.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- typescript
- Domaine
- compilers
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 42/100