135 votes

Erreur : Impossible d'invoquer une expression dont le type n'a pas de signature d'appel

Je suis tout nouveau dans le domaine du tapuscrit, et j'ai deux classes. Dans la classe mère, 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 des enfants, 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 renvoient tous deux l'erreur suivante : "Cannot invoke an expression whose type lacks a call signature" (Impossible d'invoquer une expression dont le type n'a pas de signature d'appel).

Mais la fonction renvoyée par setProp a bien une signature d'appel, je pense ? Je pense que je n'ai pas compris quelque chose d'important sur le typage des fonctions, mais je ne sais pas ce que c'est.

Merci de votre attention !

1 votes

togglrBody ne doit pas être une chaîne de caractères, puisque vous voulez qu'il s'agisse d'une fonction

1 votes

@eavidan oui c'est une fonction qui renvoie un booléen. Je pensais à l'origine qu'elle renverrait une chaîne de caractères. Je ne sais pas si c'est le cas, mais je ne sais pas si c'est le cas.

0 votes

Quel que soit le résultat de setProp, qui semble être <T>(val: T) => T

78voto

SLaks Points 391154

La fonction qu'elle renvoie possède une signature d'appel, mais vous avez demandé à Typescript de l'ignorer complètement en ajoutant : any dans sa signature.

0 votes

Ok progrès, merci ! Maintenant j'obtiens "error TS2322 : Le type '<T>(val : T) => T' n'est pas assignable au type 'boolean'". Si j'enlève le :any. Je pense que c'est la raison pour laquelle j'ai ajouté :any en premier lieu. En fait, j'obtiens toujours les erreurs d'origine.

1 votes

Si je fais cela et que je modifie public toggleBody: boolean; a public toggleBody: any; cela fonctionne.

1 votes

@Justin pourquoi t'attendais-tu à autre chose ? Vous prétendez this.toggleBody doit renvoyer boolean mais ce n'est pas cohérent avec la valeur de retour de setProp que vous lui avez attribuée. Vous semblez jeter des types au hasard sans réfléchir à ce que vous voulez réellement envoyer et renvoyer.

41voto

basarat Points 22425

"Impossible d'invoquer 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 un string en tant que fonction. D'où les erreurs sur : this.toggleBody(true); y this.toggleBody(false);

37voto

Taysky Points 3459

Voyons ce qu'il en est :

  1. L'erreur est la suivante

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

  2. Le code :

Le problème se situe au niveau de cette ligne public toggleBody: string; &

sa relation avec ces lignes :

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

Ce que vous dites toggleBody est un string mais vous le traitez comme s'il s'agissait de quelque chose qui a une call signature (c'est-à-dire la structure de quelque chose qui peut être appelé : lambdas, proc, fonctions, méthodes, etc. En JS, il s'agit simplement d'une fonction). Vous devez modifier la déclaration pour qu'elle soit public toggleBody: (arg: boolean) => boolean; .

Détails supplémentaires :

Le terme "invoquer" signifie que vous appelez ou appliquez une fonction.

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

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

"manque de 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. Vous avez dit this.toggleBody est quelque chose qui agit comme une chaîne de caractères.

En d'autres termes, l'erreur est la suivante

Impossible d'appeler une expression (this.toggleBody) car son type (:string) n'a pas de signature d'appel (car elle a une signature de type string).

4 votes

C'est l'une des meilleures réponses jamais données ! Je connais toutes ces définitions, mais lorsque j'ai vu le message d'avertissement, tous ces termes, dans une seule phrase dense, étaient trop pour mon cerveau encombré.

7voto

Gunar Gessner Points 797

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

const foo = 'string'
foo() // error

7voto

Andrew Miner Points 672

Je pense que ce que vous voulez, 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 se situe au niveau de setProp (c'est-à-dire, makePropSetter dans le nouveau code). Ce que vous faites réellement ici, c'est de dire : voici une fonction qui, pourvue d'un nom de propriété, renverra une fonction qui vous permettra de modifier cette propriété.

En <T> en makePropSetter vous permet de verrouiller cette fonction sur un type spécifique. La fonction <boolean> dans le constructeur de la sous-classe est en fait facultatif. Puisque vous assignez à toggleBody et dont le type est déjà entièrement spécifié, le compilateur TS sera en mesure de le déterminer tout seul.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X