🇺🇸 EN
Angular
·4 min read·↗·🇺🇸 EN

Cómo transformar propiedades de entrada en Angular: decoradores vs signals

Portada principal del artículo: Cómo transformar propiedades de entrada en Angular: decoradores vs signals

⚡ ¿Usas Angular moderno (v17+)? Salta directamente a Transformaciones modernas en Signal inputs con input() para ver la API idiomática con Signals.

Al diseñar componentes reutilizables, muchas veces necesitas adaptar o convertir datos que entran al componente:

  • Convertir atributos HTML de tipo string a booleanos (por ejemplo, <my-button disabled> que pasa "" en lugar de true).
  • Convertir parámetros de búsqueda o strings en números.
  • Mapear modelos de dominio externos (como una lista Course[]) a modelos de UI de terceros (como un SchedulerEvent[] para un calendario).

Históricamente, hacer esto requería escribir pares de getters y setters con mucho código repetitivo.

En esta guía práctica, te voy a mostrar cómo usar las transformaciones de inputs en Angular utilizando tanto el decorador @Input({ transform }) como la signal moderna input({ transform }).


El problema: getters y setters repetitivos

Antes de las transformaciones de inputs, convertir un booleano o formatear un objeto requería todo este código repetitivo:

// ⚠️ Enfoque legacy: Par de getter/setter tedioso
@Component({ ... })
export class MyButtonComponent {
  private _disabled = false;
 
  @Input()
  get disabled(): boolean {
    return this._disabled;
  }
  set disabled(value: boolean | string) {
    this._disabled = typeof value === 'boolean' ? value : value != null && `${value}` !== 'false';
  }
}

Ahora veamos cómo Angular moderno resuelve esto de forma declarativa.


1. Helpers integrados de conversión (booleanAttribute y numberAttribute)

Angular incluye dos funciones integradas para convertir valores:

import { Component, Input, booleanAttribute, numberAttribute } from '@angular/core';
 
@Component({
  selector: 'app-user-badge',
  standalone: true,
  template: `
    <span [class.active]="isActive">User ID: {{ userId }}</span>
  `,
})
export class UserBadgeComponent {
  // Convierte <app-user-badge is-active /> o "" en true
  @Input({ transform: booleanAttribute }) isActive = false;
 
  // Convierte "42" en 42 (number), con 0 como valor por defecto
  @Input({ transform: (val: unknown) => numberAttribute(val, 0) }) userId = 0;
}

2. Transformaciones personalizadas para mapear modelos de dominio

Las transformaciones de inputs también son excelentes para adaptar datos externos a los contratos internos de tus componentes, sin ensuciar la interfaz pública.

Por ejemplo, imagina un componente de calendario que recibe una lista Course[] desde tu aplicación, pero necesita pasar SchedulerEvent[] a un calendario de terceros:

export interface Course {
  id: string;
  title: string;
  start: Date;
  description: string;
}
 
export interface SchedulerEvent {
  id: string;
  title: string;
  start: Date;
  end: Date;
  isAllDay: boolean;
}
 
function toScheduleEvents(courses: Course[]): SchedulerEvent[] {
  return (courses || []).map((course) => ({
    id: course.id,
    title: course.title,
    start: course.start,
    end: new Date(course.start.getTime() + 2 * 60 * 60 * 1000),
    isAllDay: false,
    description: course.description,
  }));
}

Transformaciones modernas en Signal inputs con input()

En Angular moderno (v17.1+ / v19), usamos Signal inputs con input() o input.required():

// calendar.component.ts (Standalone moderno y Signal Inputs)
import { Component, input, booleanAttribute } from '@angular/core';
import { Course, SchedulerEvent, toScheduleEvents } from './calendar.models';
 
@Component({
  selector: 'app-calendar',
  standalone: true,
  template: `
    <div class="calendar-wrapper">
      @if (showGrid()) {
        <p>Total Scheduled Events: {{ events().length }}</p>
 
        @for (event of events(); track event.id) {
          <div class="event-item">
            <strong>{{ event.title }}</strong> - {{ event.start | date:'shortTime' }}
          </div>
        }
      }
    </div>
  `,
})
export class CalendarComponent {
  // 1. Conversión booleana integrada con Signal inputs
  showGrid = input(true, { transform: booleanAttribute });
 
  // 2. Transformación con mapeo personalizado: quien consume pasa Course[], el componente lee SchedulerEvent[]
  events = input.required<SchedulerEvent[], Course[]>({
    transform: toScheduleEvents,
  });
}

En la plantilla que consume el componente:

<!-- Quien consume el componente pasa Course[] crudo y el atributo string booleano de forma limpia -->
<app-calendar [events]="myCoursesList" showGrid />

Comparación: decorador @Input vs Signal input()

Característica@Input({ transform }) (v16.1+)Signal input({ transform }) (v17.1+)
ReactividadPropiedad de clase pasivaSignal reactiva (events())
Inputs requeridos@Input({ required: true, transform: ... })input.required({ transform: ... })
Listo para Zoneless🟡 Requiere ciclo de Change Detection✅ Actualizaciones precisas y granulares
Tipado estricto (Type Narrowing)(val: string | boolean) => booleanTipos explícitos de lectura y escritura con genéricos

Resumen

Las transformaciones de inputs eliminan el código repetitivo de getters y setters al convertir o mapear datos:

  1. Usa booleanAttribute para banderas HTML booleanas (<app-card shadow />).
  2. Usa numberAttribute para atributos numéricos que llegan como texto.
  3. Usa input({ transform }) con Signal inputs en Angular moderno para lograr transformaciones reactivas y con tipado seguro.
Parte de la serie Angular

These are my experiences learning and facing my daily challenges working with Angular.

Ver serie completa

Preguntas Frecuentes

¿Cuál es el propósito de la opción transform en los inputs de Angular?

La opción transform formatea, convierte o mapea valores crudos que entran al input (como atributos string o modelos de datos externos) a los tipos internos del componente, sin tener que escribir pares de getter y setter repetitivos.

¿Qué funciones de transformación integradas incluye Angular?

Angular incluye booleanAttribute (que convierte banderas string como <app-btn disabled /> en true) y numberAttribute (que convierte strings a números de forma segura con valores por defecto).

¿Cómo se usan las transformaciones de inputs con las Signal inputs modernas de Angular?

Pasa una función de transformación en las opciones de la signal input: input(false, { transform: booleanAttribute }) o input.required<User, RawUser>({ transform: toUser }).

¿Puede una función transform cambiar el tipo de TypeScript que aceptan los templates que consumen el componente?

Sí. Las transformaciones de inputs en Angular soportan tipos de escritura distintos (lo que pasa el template consumidor) y tipos de lectura (lo que lee el código del componente internamente).

Artículos Relacionados

Compartir este artículo

Si esta guía te resultó útil, compártela con tu equipo o con otros desarrolladores.


Software real. Lecciones reales.

Comparto las lecciones que aprendí por las malas, para que puedas evitarlas o estar preparado cuando ocurran.

User avatar
User avatar
User avatar
User avatar
+13K

Únete a 13,800+ desarrolladores y lectores.

Cero spam. Cancela tu suscripción en cualquier momento.