Erreur: impossible d'appeler une expression dont le type n'a pas de signature d'appel

121

Je suis tout nouveau dactylographié et j'ai deux classes. Dans la classe des parents, j'ai:

abstract class Component {
  public deps: any = {};
  public props: any = {};

  public setProp(prop: string): any {
    return <T>(val: T): T => {
      this.props[prop] = val;
      return val;
    };
  }
}

Dans la classe enfant, j'ai:

class Post extends Component {
  public toggleBody: string;

  constructor() {
    this.toggleBody = this.setProp('showFullBody');
  }

  public showMore(): boolean {
    return this.toggleBody(true);
  }

  public showLess(): boolean {
    return this.toggleBody(false);
  }
}

ShowMore et ShowLess me donnent tous les deux l'erreur "Impossible d'appeler une expression dont le type n'a pas de signature d'appel."

Mais la fonction que setProp retourne a-t-elle une signature d'appel, je pense? Je pense que je ne comprends pas quelque chose d'important sur les typages de fonctions, mais je ne sais pas ce que c'est.

Merci!

Justin
la source
1
togglrBodyne devrait pas être une chaîne, puisque vous voulez que ce soit une fonction
eavidan
1
@eavidan oui c'est une fonction qui renvoie en fait un booléen. Je pensais au départ que cela renverrait une chaîne. Alors, qu'est-ce que je change?
Justin le
Quel que soit le retour de setProp, ce qui semble être<T>(val: T) => T
eavidan

Réponses:

76

La fonction qu'elle renvoie a une signature d'appel, mais vous avez dit à Typescript d'ignorer complètement cela en ajoutant : anysa signature.

Ne fais pas ça.

SLaks
la source
Ok progrès, merci! Maintenant, j'obtiens "l'erreur TS2322: le type '<T> (val: T) => T' n'est pas attribuable au type 'booléen'." Si je supprime le: any. Je pense que c'est pour cela que j'ai ajouté: tout en premier lieu. En fait, j'obtiens toujours les erreurs d'origine.
Justin le
1
Si je fais ça et le changement public toggleBody: boolean;à public toggleBody: any;cela fonctionne.
Justin le
1
@Justin pourquoi vous attendiez-vous à autre chose? Vous déclarez this.toggleBodydevoir retourner boolean, mais ce n'est pas cohérent avec la valeur de retour setPropque vous lui avez attribuée. Vous semblez simplement lancer des types au hasard sans penser à ce que vous voulez réellement envoyer et renvoyer.
jonrsharpe
@jonrsharpe Ok oui cela a du sens. Dans ce cas, il renvoie un booléen, mais en général, il en renvoie un. Alors je dois en utiliser?
Justin le
9
Cette réponse gagnerait à expliquer la bonne façon de faire les choses, avec un exemple.
Andre M
38

"Impossible d'appeler une expression dont le type n'a pas de signature d'appel."

Dans votre code:

class Post extends Component {
  public toggleBody: string;

  constructor() {
    this.toggleBody = this.setProp('showFullBody');
  }

  public showMore(): boolean {
    return this.toggleBody(true);
  }

  public showLess(): boolean {
    return this.toggleBody(false);
  }
}

Vous avez public toggleBody: string;. Vous ne pouvez pas appeler stringune fonction. D'où des erreurs sur: this.toggleBody(true);etthis.toggleBody(false);

basarat
la source
28

Décomposons ceci:

  1. L'erreur dit

    Impossible d'appeler une expression dont le type n'a pas de signature d'appel.

  2. Le code:

Le problème est dans cette ligne public toggleBody: string;et

c'est en relation avec ces lignes:

...
return this.toggleBody(true);
...
return this.toggleBody(false);
  1. Le résultat:

Votre dicton toggleBodyest un stringmais alors vous le traitez comme quelque chose qui a un call signature(c'est-à-dire la structure de quelque chose qui peut être appelé: lambdas, proc, fonctions, méthodes, etc. En JS, fonction juste tho.). Vous devez changer la déclaration pour être public toggleBody: (arg: boolean) => boolean;.

Détails supplémentaires:

"invoke" signifie votre appel ou l'application d'une fonction.

"une expression" en Javascript est essentiellement quelque chose qui produit une valeur, donc this.toggleBody()compte comme une expression.

"type" est déclaré sur cette ligne public toggleBody: string

"manque une signature d'appel" c'est parce que vous essayez d'appeler quelque chose this.toggleBody()qui n'a pas de signature (c'est-à-dire la structure de quelque chose qui peut être appelé: lambdas, proc, fonctions, méthodes, etc.) qui peut être appelée. Vous avez dit que this.toggleBodyc'est quelque chose qui agit comme une corde.

En d'autres termes, l'erreur dit

Impossible d'appeler une expression (this.toggleBody) car son type (: string) n'a pas de signature d'appel (bc il a une signature de chaîne.)

Taysky
la source
4
C'est l'une des meilleures réponses de tous les temps! Je connais toutes ces définitions, mais quand j'ai vu le message d'avertissement, tous ces termes, en une phrase dense, étaient trop pour mon cerveau encombré.
cham
6

Je pense que ce que tu veux c'est:

abstract class Component {
  public deps: any = {};
  public props: any = {};

  public makePropSetter<T>(prop: string): (val: T) => T {
    return function(val) {
      this.props[prop] = val
      return val
    }
  }
}

class Post extends Component {
  public toggleBody: (val: boolean) => boolean;

  constructor () {
    super()
    this.toggleBody = this.makePropSetter<boolean>('showFullBody')
  }

  showMore (): boolean {
    return this.toggleBody(true)
  }

  showLess (): boolean {
    return this.toggleBody(false)
  }
}

Le changement important est dans setProp(c'est- makePropSetterà- dire dans le nouveau code). Ce que vous faites vraiment là-bas, c'est dire: c'est une fonction, qui munie d'un nom de propriété, retournera une fonction qui vous permet de changer cette propriété.

Le <T>sur makePropSettervous permet de verrouiller cette fonction pour un type spécifique. Le constructeur <boolean>de la sous-classe est en fait facultatif. Puisque vous affectez à toggleBody, et que le type est déjà entièrement spécifié, le compilateur TS pourra le résoudre lui-même.

Ensuite, dans votre sous-classe, vous appelez cette fonction, et le type de retour est maintenant correctement compris comme une fonction avec une signature spécifique. Naturellement, vous devrez toggleBodyrespecter cette même signature.

Andrew Miner
la source
5

Cela signifie que vous essayez d'appeler quelque chose qui n'est pas une fonction

const foo = 'string'
foo() // error
Gunar Gessner
la source
0

Ajoutez un type à votre variable, puis revenez.

Par exemple:

const myVariable : string [] = ['hello', 'there'];

const result = myVaraible.map(x=> {
  return
  {
    x.id
  }
});

=> La partie importante est l'ajout de la chaîne [] type etc:

Afshin Ghazi
la source
0

J'ai eu le même message d'erreur. Dans mon cas, j'avais mélangé par inadvertance la export default function myFuncsyntaxe ES6 avec const myFunc = require('./myFunc');.

L'utilisation à la module.exports = myFunc;place a résolu le problème.

Charlie Weems
la source
0

Cette erreur peut être provoquée lorsque vous demandez une valeur à quelque chose et que vous mettez des parenthèses à la fin, comme s'il s'agissait d'un appel de fonction, mais la valeur est correctement récupérée sans mettre fin aux parenthèses. Par exemple, si vous accédez à une propriété «get» dans Typescript.

private IMadeAMistakeHere(): void {
    let mynumber = this.SuperCoolNumber();
}

private IDidItCorrectly(): void {
    let mynumber = this.SuperCoolNumber;
}

private get SuperCoolNumber(): number {
    let response = 42;
    return response;
};
StackOverflowUser
la source