2017-09-10 9 views
2

j'avoir un exemple des fonctions suivantes (Compose est de Ramda):tapuscrit question de l'inférence de type lorsque la fonction retourne fonction

declare function compose<V0, T1, T2>(fn1: (x: T1) => T2, fn0: (x0: V0) => T1): (x0: V0) => T2; 

    interface User { 
     id: number 
    } 

    function fn1(input: any): User { 
     return {id: 1}; 
    } 

    function fn2<I, O>(fn: (i: I) => O): (i: I) => O { 
     return (data) => { 
     try { 
      return fn(data); 
     } catch (e) { 
      return undefined 
     } 
     }; 
    } 

Lorsque j'ai essayé de l'utiliser comme ceci:

compose(fn2(user => user.id), fn1); 

tapuscrit jette un erreur suivant:

TS2339:Property 'id' does not exist on type '{}'.

quelqu'un at-kno w, que dois-je faire pour aider TypeScript à déduire un type correct pour user?

Bien sûr, le code suivant fonctionnera:

compose<any, User, number>(fn2(user => user.id), fn1); 
+0

MISE À JOUR: On dirait que l'équipe dactylographiée est au courant de ce comportement , du moins, ce n'est pas un bug. Voir [ce commentaire] (https://github.com/Microsoft/TypeScript/issues/15680#issuecomment-307571917). – Deftomat

Répondre

1

Il semble que les types comme paramétriques sont résolus de gauche à droite et parce que vous écrivez un tout à une fonction première que vous avez cette erreur. Regardez ce code qui est similaire, mais les fonctions sont inversées:

declare function compose<V0, T1, T2>(fn0: (x0: V0) => T1, fn1: (x: T1) => T2,): (x0: V0) => T2; 

interface User { 
    id: number 
} 

function fn1(input: number): User { 
    return {id: 1}; 
} 

function fn2<I, O>(fn: (i: I) => O): (i: I) => O { 
    return (data) => { 
    try { 
     return fn(data); 
    } catch (e) { 
     return undefined 
    } 
    }; 
} 

compose(fn1, fn2(user => user.id)); 

Cela fonctionne comme vous vous y attendez. mais la définition de composer doit être changée.

Modifier

similaires à la réponse de Titian Cernicova, vous pouvez définir au moins le premier élément paramétrique qui va dans votre chaîne de composition comme ceci:

declare function compose<T1 = any, T2 = any, V0 = any>(fn1: (x: T1) => T2, fn0: (x0: V0) => T1): (x0: V0) => T2; 

interface User { 
    id: number 
} 

function fn1(input: number): User { 
    return {id: 1}; 
} 

function fn2<I, O>(fn: (i: I) => O): (i: I) => O { 
    return (data) => { 
    try { 
     return fn(data); 
    } catch (e) { 
     return undefined 
    } 
    }; 
} 

compose<User>(fn2(user => user.id), fn1); 
+0

Merci, je ne sais pas si c'est un bug ou juste une limitation de TypeScript. Selon votre idée, j'ai décidé d'utiliser [pipe] (http://ramdajs.com/docs/#pipe), ce qui me permet d'utiliser des fonctions dans l'ordre inverse. – Deftomat

0

Vous ne devez pas spécifier tous les types, mais vous devez spécifier le type de paramètre user pour que cela fonctionne.

compose(fn2((user: User) => user.id), fn1); 

Si vous deviez ne pas utiliser fn2 inférence de type fonctionnerait, mais décidant que l » argument fn2 doit être de type (user:User)=> number en fonction de la valeur qui doit être retourné par Fn2 est un peu trop pour le tapuscrit compilateur.

Cela fonctionne:

compose((user) => user.id, fn1);