Una función de TypeScript es una función de JavaScript con tipos en sus parámetros y, opcionalmente, en su valor de retorno. Cada parámetro lleva una anotación, el tipo de retorno va después de la lista de parámetros y el compilador comprueba cada llamada contra ambos.
Las dos llamadas incorrectas son errores en tiempo de compilación (TS2345 y TS2554). Los comentarios // @ts-expect-error le dicen al compilador que se espera un error en la línea siguiente, así que el resto del archivo se ejecuta igualmente. Quita uno de ellos y vuelve a ejecutar para ver el mensaje real.
Tipos de los parámetros
Cada parámetro se escribe name: Type. Con strict, que en TypeScript 7 está activado por defecto, un parámetro sin anotación y sin contexto del que inferir es un error: Parameter 'x' implicitly has an 'any' type. (TS7006). Así que en la práctica se anotan todos los parámetros de una función independiente.
Cualquier tipo sirve como tipo de parámetro: primitivos, arrays, tipos objeto, uniones, otras funciones.
TypeScript también comprueba el número de argumentos. Pasar más o menos de los que declara la función es un error, a diferencia de JavaScript normal, que rellena los que faltan con undefined e ignora los que sobran. Para hacer opcional un parámetro o darle un valor por defecto, consulta parámetros opcionales.
Tipos de retorno: anotar o inferir
El tipo de retorno va después del paréntesis de cierre: function f(): Type. Es opcional. Sin él, TypeScript infiere el tipo a partir de cada return del cuerpo.
Una anotación vale la pena cuando la función se exporta, cuando tiene varios caminos de retorno o cuando es recursiva. El error aparece entonces dentro de la función, en el return equivocado, y no en quien la llama. Un caso clásico es una rama que se olvida de devolver:
El compilador informa index.ts(2,32): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. Añade un return "C"; final y se ejecuta. Sin la anotación : string, la función compilaría con el tipo inferido "A" | "B" | undefined, y el problema pasaría a quien use el resultado.
void: funciones que no devuelven nada
Una función que solo hace algo (escribe en el log, guarda, modifica) tiene el tipo de retorno void. Es lo que infiere TypeScript cuando no hay ningún return con valor, y también puedes escribirlo de forma explícita.
Estas reglas sobre void sorprenden:
| Situación | ¿Permitido? |
|---|---|
function f(): void { return 42; } | No: Type 'number' is not assignable to type 'void'. (TS2322) |
const f: () => void = () => 42; | Sí: el valor se devuelve, pero quien llama no debe contar con él |
function f(): undefined {} | Sí (TypeScript 5.1 y posteriores) |
Usar el resultado de una función void en un if | No: An expression of type 'void' cannot be tested for truthiness. (TS1345) |
La segunda fila es deliberada. Es la razón por la que arr.forEach(x => list.push(x)) compila aunque push devuelva un número. void en un tipo de función significa «devuelva lo que devuelva, nadie lo lee». Para una función que nunca termina (siempre lanza o no sale nunca de un bucle), el tipo de retorno es never.
Funciones flecha y expresiones de función
Las funciones flecha y las expresiones de función llevan las mismas anotaciones. El tipo de retorno va después de la lista de parámetros, antes de =>.
Sin los paréntesis, (x, y) => { x, y } es un bloque sin return, y la función devuelve undefined. Las reglas de ejecución de las funciones flecha (sin this propio, sin arguments) son las mismas que en JavaScript; consulta funciones flecha en JavaScript.
Cuando una función se escribe en línea como argumento, normalmente no anotas sus parámetros. TypeScript sabe qué recibe el callback por la función a la que se pasa (tipado contextual): en [1, 2].map(n => n * 2), n ya es number. Cómo escribir el tipo de una función como valor, (n: number) => string, se explica en tipos de función.
Devolver varios valores
Una función devuelve un solo valor, así que devuelve un objeto o una tupla y desestructúralo.
El tipo de retorno tupla necesita la anotación. Sin ella, [a, b] se infiere como string[]: la desestructuración sigue funcionando, pero el tipo ya no dice que haya exactamente dos elementos.
Funciones async
Una función async siempre devuelve una Promise. Anota el tipo de retorno como Promise<T>, donde T es lo que devuelve la función por dentro.
async function loadScore(id: number): Promise<number> {
await new Promise((resolve) => setTimeout(resolve, 10));
return id * 10;
}
async function main(): Promise<void> {
const score = await loadScore(4); // score: number
console.log("score", score);
}
main();
Escribir async function f(): number es un error: The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<number>'? (TS1064).
El parámetro this
JavaScript decide this en el momento de la llamada. TypeScript te permite declarar qué debe ser this con un primer parámetro ficticio llamado this. Se elimina del JavaScript compilado y quien llama no lo pasa.
interface Counter {
count: number;
}
function increment(this: Counter, by: number): void {
this.count += by;
}
const c = { count: 0, increment };
c.increment(2); // fine: this is c
increment(2);
// error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Counter'.
Sin el parámetro this, this dentro de una función independiente es un any implícito y el modo strict informa 'this' implicitly has type 'any' because it does not have a type annotation. (TS2683). En los métodos de clase this ya tiene el tipo de la instancia, así que el parámetro es útil sobre todo para funciones independientes asignadas a objetos y para callbacks que las librerías llaman con un this concreto.
Preguntas frecuentes
¿Cómo se indica el tipo de retorno de una función en TypeScript?
Escribe dos puntos y el tipo después de la lista de parámetros: function total(a: number, b: number): number { ... }. En una función flecha va en el mismo sitio: const total = (a: number, b: number): number => a + b;. Si lo omites, TypeScript infiere el tipo de retorno a partir de las sentencias return.
¿Debo anotar siempre el tipo de retorno en TypeScript?
Es opcional, porque el tipo de retorno se infiere. Anótalo en las funciones exportadas y en las funciones con varios caminos de return: la anotación documenta el contrato, y un return equivocado se informa entonces dentro de la función en lugar de en alguna llamada lejana.
¿Qué diferencia hay entre void y undefined en TypeScript?
void significa "quien llama no debe usar el valor de retorno". undefined es un tipo de valor concreto. Una función declarada (): void no puede devolver un valor, pero un tipo de callback () => void acepta una función que sí devuelve algo, y el resultado simplemente se ignora. Usa void para funciones que no devuelven nada y undefined solo cuando quien llama compara de verdad el resultado con undefined.
¿Cómo devuelvo varios valores desde una función de TypeScript?
Devuelve un objeto ({ min: number; max: number }) o una tupla ([number, number]) y desestructúralo al llamar. Los objetos son más claros cuando los valores significan cosas distintas; las tuplas se leen bien para pares cortos como [value, setValue].
¿Cuál es el tipo de retorno de una función async en TypeScript?
Siempre una Promise. Una función async que devuelve un number tiene el tipo de retorno Promise<number>, y escribirle : number es un error de compilación (TS1064). Una función que no devuelve nada es Promise<void>.