Error: no se puede invocar una expresión cuyo tipo carece de una firma de llamada

121

Soy nuevo en mecanografiado y tengo dos clases. En la clase de padres tengo:

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

En la clase infantil tengo:

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

Tanto showMore como ShowLess me dan el error "No se puede invocar una expresión cuyo tipo carece de una firma de llamada".

Pero la función que devuelve setProp TIENE una firma de llamada, creo. Creo que estoy malinterpretando algo importante sobre la tipificación de funciones, pero no sé qué es.

¡Gracias!

Justin
fuente
1
togglrBodyno debe ser una cadena, ya que quieres que sea una función
eavidan
1
@eavidan sí, es una función que en realidad devuelve un booleano. Originalmente pensé que devolvería una cadena. Entonces, ¿a qué lo cambio?
Justin
Sea lo que sea que regrese setProp, que parece<T>(val: T) => T
eavidan

Respuestas:

76

La función que devuelve tiene una firma de llamada, pero le dijo a TypeScript que lo ignorara por completo agregando : anysu firma.

No hagas eso.

SLaks
fuente
Ok progreso, gracias! Ahora aparece el "error TS2322: el tipo '<T> (val: T) => T' no se puede asignar al tipo 'booleano'". Si elimino el: any. Creo que por eso agregué: cualquiera en primer lugar. De hecho, todavía obtengo los errores originales también.
Justin
1
Si hago esto y el cambio public toggleBody: boolean;a public toggleBody: any;su funcionamiento.
Justin
1
@Justin, ¿por qué esperabas algo más? Usted afirma que this.toggleBodydebería regresar boolean, pero eso no es consistente con el valor de retorno setPropque le ha asignado. Parece que estás introduciendo tipos al azar sin pensar en lo que realmente quieres enviar y devolver.
jonrsharpe
@jonrsharpe Ok, sí, eso tiene sentido. En este caso, devuelve un booleano, pero en general devuelve cualquier. ¿Entonces tengo que usar alguno?
Justin
9
Esta respuesta se beneficiaría de explicar la forma correcta de hacer las cosas, con un ejemplo.
Andre M
38

"No se puede invocar una expresión cuyo tipo carece de una firma de llamada".

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

Tienes public toggleBody: string;. No puede llamar a stringcomo función. De ahí errores en: this.toggleBody(true);ythis.toggleBody(false);

basarat
fuente
28

Analicemos esto:

  1. El error dice

    No se puede invocar una expresión cuyo tipo carece de una firma de llamada.

  2. El código:

El problema está en esta línea public toggleBody: string;y

su relación con estas líneas:

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

Tu dicho toggleBodyes un stringpero luego lo tratas como algo que tiene un call signature(es decir, la estructura de algo que se puede llamar: lambdas, proc, funciones, métodos, etc. En JS simplemente funciona aunque). Necesita cambiar la declaración para que sea public toggleBody: (arg: boolean) => boolean;.

Detalles adicionales:

"invocar" significa su llamada o aplicación de una función.

"una expresión" en Javascript es básicamente algo que produce un valor, por lo que this.toggleBody()cuenta como una expresión.

"tipo" se declara en esta línea public toggleBody: string

"carece de una firma de llamada" esto se debe a que estás intentando llamar a algo this.toggleBody()que no tiene firma (es decir, la estructura de algo que se puede llamar: lambdas, proc, funciones, métodos, etc.) que se puede llamar. Dijiste que this.toggleBodyes algo que actúa como una cuerda.

En otras palabras, el error es decir

No se puede llamar a una expresión (this.toggleBody) porque su tipo (: cadena) carece de una firma de llamada (porque tiene una firma de cadena).

Taysky
fuente
4
¡Esta es una de las mejores respuestas de todas! Conozco todas esas definiciones, pero cuando vi el mensaje de advertencia, todos esos términos, en una oración densa, fueron demasiado para mi cerebro desordenado.
cham
6

Creo que lo que quieres es:

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

El cambio importante está en setProp(es decir, makePropSetteren el nuevo código). Lo que realmente está haciendo allí es decir: esta es una función, que si se le proporciona un nombre de propiedad, devolverá una función que le permite cambiar esa propiedad.

El <T>encendido le makePropSetterpermite bloquear esa función en un tipo específico. El <boolean>en el constructor de la subclase es en realidad opcional. Dado que está asignando a toggleBody, y que ya tiene el tipo completamente especificado, el compilador de TS podrá resolverlo por sí solo.

Luego, en su subclase, llama a esa función, y el tipo de retorno ahora se entiende correctamente como una función con una firma específica. Naturalmente, deberás toggleBodyrespetar esa misma firma.

Andrew Miner
fuente
5

Significa que estás intentando llamar a algo que no es una función.

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

Agregue un tipo a su variable y luego regrese.

P.ej:

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

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

=> La parte importante es agregar el tipo de cadena [], etc.

Afshin Ghazi
fuente
0

Tuve el mismo mensaje de error. En mi caso, sin darme cuenta había mezclado la export default function myFuncsintaxis de ES6 con const myFunc = require('./myFunc');.

Usar en su module.exports = myFunc;lugar resolvió el problema.

Charlie Weems
fuente
0

Este error se puede producir cuando solicita un valor de algo y pone paréntesis al final, como si fuera una llamada a una función, pero el valor se recupera correctamente sin terminar el paréntesis. Por ejemplo, si lo que está accediendo es una propiedad 'obtener' en Typecript.

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

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

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