Inferencia, defaults y const type parameters | Nicolás Garzón
TypeScript
Copiar function wrap < T > ( value: T ) : { value: T } {
return { value } ;
}
const result = wrap ( "hello" ) ;
El literal puede ampliarse según el contexto y mutabilidad.
TypeScript
Copiar function pair < T > ( first: T , second: T ) : [ T , T ] {
return [ first, second] ;
} TypeScript
Copiar pair ( 1 , 2 ) ;
TypeScript
Copiar pair ( 1 , "two" ) ; Puede fallar porque el primer argumento conduce a una inferencia incompatible. Si quieres permitir mezcla, utiliza dos parámetros de tipo:
TypeScript
Copiar function pair < TFirst, TSecond> (
first: TFirst,
second: TSecond,
) : [ TFirst, TSecond] {
return [ first, second] ;
} TypeScript
Copiar const loader : ( ) => Promise < Product> =
async ( ) => loadUnknownProduct ( ) ; El contexto participa en la comprobación, pero no valida datos externos.
TypeScript
Copiar const empty = createCollection < Product> ( ) ; Es útil cuando no hay argumento del cual inferir.
TypeScript no permite normalmente especificar algunos type arguments y dejar otros como placeholders arbitrarios.
TypeScript
Copiar function convert < TInput, TOutput> ( value: TInput) : TOutput; Diseña el orden de parámetros, defaults o una factory curried para permitir inferencia útil.
TypeScript
Copiar type ApiResponse< TData = unknown > = {
data: TData;
} ; TypeScript
Copiar const response: ApiResponse = {
data: externalValue,
} ; El default se usa cuando no existe un type argument explícito ni inferido.
Los parámetros requeridos no pueden aparecer después de uno opcional sin defaults adecuados.
TypeScript
Copiar type Result< TValue, TError = Error> =
| { ok: true ; value: TValue }
| { ok: false ; error: TError } ; TypeScript
Copiar type Collection<
TItem extends { id: string } = { id: string } ,
> = {
items: TItem[ ] ;
} ; El default debe cumplir el constraint.
TypeScript
Copiar function defineRoutes < const TRoutes extends readonly Route[ ] > (
routes: TRoutes,
) : TRoutes {
return routes;
} TypeScript
Copiar const routes = defineRoutes ( [
{ path: "/" , public : true } ,
{ path: "/admin" , public : false } ,
] ) ; const favorece inferencia literal y readonly para expresiones creadas en la llamada, similar a aplicar as const en el sitio apropiado.
TypeScript
Copiar function define < const T > ( value: T ) : T {
return value;
} const type parameter solo cambia inferencia. No ejecuta Object.freeze.
TypeScript
Copiar function define < const T extends string [ ] > ( value: T ) : T {
return value;
} Un array literal readonly inferido puede no cumplir string[], haciendo que TypeScript vuelva a un constraint más amplio. Usa un constraint readonly cuando quieres conservar literals:
TypeScript
Copiar function define < const T extends readonly string [ ] > (
value: T ,
) : T {
return value;
} NoInfer<T> bloquea una ubicación como fuente de inferencia sin cambiar el tipo final.
TypeScript
Copiar function createState < T > (
initialValue: T ,
defaultValue? : NoInfer< T > ,
) : T {
return initialValue ?? defaultValue! ;
} El tipo se infiere desde initialValue; defaultValue debe ajustarse a esa decisión en lugar de ampliarla.
TypeScript
Copiar function createFSM < TState extends string > (
states: readonly TState[ ] ,
initial: NoInfer< TState> ,
) { } TypeScript
Copiar createFSM (
[ "idle" , "loading" , "success" ] as const ,
"idle" ,
) ; initial se comprueba contra la union derivada de states.
Cuando un type parameter aparece en parámetros de callback, retorno y valores, TypeScript reúne candidatos con reglas de variance y prioridad. Diseña APIs simples; no dependas de una inferencia misteriosa que solo funciona en un ejemplo.
TypeScript
Copiar function createValidator < T > ( ) {
return < TValue extends T > ( value: TValue) : TValue => value;
}
const validateProduct = createValidator < Product> ( ) ; Separa un type argument explícito de otros inferidos después.
TypeScript
Copiar function defineEvents <
const TEvents extends Record< string , unknown > ,
> ( events: TEvents) : TEvents {
return events;
}
const events = defineEvents ( {
"product.created" : { } as ProductCreated,
"product.deleted" : { } as ProductDeleted,
} ) ;
Especificar type arguments que pueden inferirse.
Esperar partial inference automática.
Colocar defaults en orden poco utilizable.
Usar const type parameter creyendo que congela valores.
Mantener constraints mutables y perder literals readonly.
Usar NoInfer como solución a una API confusa.
Hacer que demasiados argumentos compitan por inferir T.
Forzar una inferencia mediante assertions.
TypeScript infiere desde argumentos y contexto.
Varios parámetros de tipo preservan relaciones independientes.
Defaults cubren ausencia de inferencia o type argument.
const type parameters favorecen inferencia literal.
NoInfer decide qué posición no debe influir en T.
Ninguna herramienta de inferencia cambia el runtime.
El diseño de la firma determina la calidad de la inferencia.
¿Por qué un const type parameter no reemplaza Object.freeze?
Respuesta Porque solo conserva tipos literales y readonly durante el análisis; no añade ninguna operación al JavaScript emitido.
Interfaces, clases y factories genéricas aplica parámetros de tipo a contratos reutilizables y construcción.