Erro: não é possível invocar uma expressão cujo tipo não possui uma assinatura de chamada

121

Eu sou novo em datilografado e tenho duas classes. Na classe pai eu tenho:

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;
    };
  }
}

Na classe infantil, tenho:

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 e ShowLess me dão o erro "Não é possível invocar uma expressão cujo tipo não possui assinatura de chamada".

Mas a função que setProp retorna TEM uma assinatura de chamada, eu acho? Acho que estou entendendo mal algo importante sobre tipos de funções, mas não sei o que é.

Obrigado!

Justin
fonte
1
togglrBodynão deve ser uma string, desde que você quer que ele seja uma função
eavidan
1
@eavidan sim, é uma função que realmente retorna um booleano. Eu originalmente pensei que retornaria uma string. Então, para que eu mudo?
Justin
Qualquer setProp retorna, o que parece ser<T>(val: T) => T
eavidan

Respostas:

76

A função que ele retorna possui uma assinatura de chamada, mas você disse ao Typescript para ignorá-lo completamente, adicionando : anysua assinatura.

Não faça isso.

SLaks
fonte
Ok progresso, obrigado! Agora, recebo "erro TS2322: Digite '<T> (val: T) => T' não é atribuível ao tipo 'booleano'." Se eu remover o: any. Eu acho que foi por isso que acrescentei: qualquer em primeiro lugar. Na verdade, ainda recebo os erros originais também.
Justin justin do comentário
1
Se eu fizer isso e mudar public toggleBody: boolean;para public toggleBody: any;ele funciona.
Justin justin do comentário
1
@ Justin, por que você esperava mais alguma coisa? Você alega que this.toggleBodydeve retornar boolean, mas isso não é consistente com o valor de retorno setPropatribuído a ele. Parece que você está jogando aleatoriamente tipos sem pensar no que realmente deseja enviar e retornar.
precisa saber é o seguinte
@ Jonrsharpe Ok, sim, isso faz sentido. Nesse caso, ele retorna um booleano, mas, em geral, retorna any. Então eu tenho que usar algum?
Justin
9
Essa resposta se beneficiaria de explicar a maneira correta de fazer as coisas, com um exemplo.
Andre M
38

"Não é possível invocar uma expressão cujo tipo não possui uma assinatura de chamada."

No seu código:

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);
  }
}

Você tem public toggleBody: string;. Você não pode chamar a stringcomo uma função. Daí erros em: this.toggleBody(true);ethis.toggleBody(false);

basarat
fonte
28

Vamos dividir isso:

  1. O erro diz

    Não é possível invocar uma expressão cujo tipo não possui uma assinatura de chamada.

  2. O código:

O problema está nesta linha public toggleBody: string;e

é relação com estas linhas:

...
return this.toggleBody(true);
...
return this.toggleBody(false);
  1. O resultado:

Seu ditado toggleBodyé um, stringmas então você o trata como algo que tem um call signature(ou seja, a estrutura de algo que pode ser chamado: lambdas, proc, funções, métodos, etc. No JS, apenas funciona tho.). Você precisa alterar a declaração para ser public toggleBody: (arg: boolean) => boolean;.

Detalhes extras:

"invocar" significa sua chamada ou aplicação de uma função.

"uma expressão" em Javascript é basicamente algo que produz um valor, então this.toggleBody()conta como uma expressão.

"type" é declarado nesta linha public toggleBody: string

"falta uma assinatura de chamada" é porque você está tentando chamar algo this.toggleBody()que não tem assinatura (ou seja, a estrutura de algo que pode ser chamado: lambdas, proc, funções, métodos, etc.) que podem ser chamados. Você disse que this.toggleBodyé algo que age como uma corda.

Em outras palavras, o erro está dizendo

Não é possível chamar uma expressão (this.toggleBody) porque seu tipo (: string) não possui uma assinatura de chamada (bc, ela possui uma assinatura de string).

Taysky
fonte
4
Esta é uma das melhores respostas, sempre! Conheço todas essas definições, mas quando vi a mensagem de aviso, todos esses termos, em uma sentença densa, eram demais para o meu cérebro confuso.
194/02
6

Eu acho que o que você quer é:

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)
  }
}

A mudança importante está em setProp(ou seja, makePropSetterno novo código). O que você realmente está fazendo lá é dizer: esta é uma função, que é fornecida com um nome de propriedade, retornará uma função que permite alterar essa propriedade.

O <T>on makePropSetterpermite bloquear essa função em um tipo específico. O <boolean>construtor da subclasse é realmente opcional. Como você está atribuindo a toggleBody, e que já possui o tipo totalmente especificado, o compilador TS poderá resolver isso sozinho.

Em sua subclasse, você chama essa função e o tipo de retorno agora é entendido como uma função com uma assinatura específica. Naturalmente, você precisará toggleBodyrespeitar a mesma assinatura.

Andrew Miner
fonte
5

Isso significa que você está tentando chamar algo que não é uma função

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

Adicione um tipo à sua variável e, em seguida, retorne.

Por exemplo:

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

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

=> Parte importante é adicionar o tipo de string [] etc:

Afshin Ghazi
fonte
0

Eu tive a mesma mensagem de erro. No meu caso, misturei inadvertidamente a export default function myFuncsintaxe do ES6 const myFunc = require('./myFunc');.

O uso module.exports = myFunc;resolveu o problema.

Charlie Weems
fonte
0

Este erro pode ser causado quando você solicita um valor de alguma coisa e coloca parênteses no final, como se fosse uma chamada de função, mas o valor é recuperado corretamente sem terminar o parêntese. Por exemplo, se o que você está acessando é uma propriedade 'get' no 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
fonte