Restringes tus parámetros de tipo con extends y proporcionas valores por defecto para construir API genéricas ergonómicas.
Abrir esta lección en KodokonUn genérico sin restricción es opaco: dentro del cuerpo de la función, T no te deja hacer nada. La cláusula extends establece un contrato mínimo sobre el parámetro de tipo, lo que desbloquea el acceso a las propiedades garantizadas conservando a la vez el tipo preciso de quien llama. Esa es la diferencia fundamental con un parámetro tipado con una interfaz: la restricción conserva la información, la interfaz la borra.
function longest<T extends { length: number }>(
a: T,
b: T
): T {
return a.length >= b.length ? a : b;
}
const word = longest("hello", "worldwide");
const list = longest([1, 2], [3, 4, 5]);El dúo K extends keyof T es el patrón cotidiano más rentable: enlaza dos parámetros de tipo entre sí y garantiza estáticamente que una clave pertenece realmente al objeto. El tipo de retorno T[K] (un tipo de acceso indexado) sigue con precisión la propiedad solicitada. Así es exactamente como se tipan funciones como pick o pluck de las librerías de utilidades.
function getProp<T extends object, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key];
}
const config = { port: 8080, host: "localhost" };
const port = getProp(config, "port");
const host = getProp(config, "host");Los valores por defecto (T = string) hacen que un genérico sea opcional en el sitio de la llamada: los usuarios solo proporcionan el argumento de tipo cuando quieren desviarse del caso común. Combinados con una restricción (T extends X = Y), definen a la vez el límite y el comportamiento implícito. El valor por defecto debe satisfacer la restricción, de lo contrario la propia declaración no compila. Es el patrón estándar para clientes HTTP, stores y emisores de eventos tipados.
interface ApiResponse<T = unknown> {
status: number;
data: T;
}
async function fetchJson<T = unknown>(
url: string
): Promise<ApiResponse<T>> {
const res = await fetch(url);
return { status: res.status, data: await res.json() };
}
interface Post { id: number; title: string }
const typed = await fetchJson<Post>("/api/posts/1");
const loose = await fetchJson("/api/health");K extends keyof T en una firma genérica?longest<T extends { length: number }> sobre longest(a: { length: number }, b: ...) sin genéricos?<T = unknown> en lugar de <T = any> como valor por defecto?