void main() {
String nombre = "Flutter";
int edad = 7;
double version = 3.0;
bool esModerno = true;
print('$nombre tiene $edad años y versión $version');
}
function main(): void {
const nombre: string = "Angular";
const edad: number = 14;
const version: number = 17.0;
const esModerno: boolean = true;
console.log(`${nombre} tiene ${edad} años y versión ${version}`);
}
Diferencias clave:
- Dart usa
void main()
como punto de entrada - TypeScript requiere configuración adicional para ejecutar
- Dart tiene interpolación de strings con
$variable
- TypeScript usa template literals con
${variable}
void ejemploListas() {
// Lista dinámica
List<int> numeros = [1, 2, 3, 4, 5];
List<String> frutas = ['manzana', 'banana', 'naranja'];
// Lista fija
List<int> numerosFijos = List.filled(3, 0);
// Operaciones
numeros.add(6);
numeros.insert(0, 0);
numeros.removeAt(1);
// Métodos funcionales
var pares = numeros.where((n) => n % 2 == 0).toList();
var duplicados = numeros.map((n) => n * 2).toList();
print('Números: $numeros');
print('Pares: $pares');
}
function ejemploArrays(): void {
// Arrays dinámicos
const numeros: number[] = [1, 2, 3, 4, 5];
const frutas: string[] = ['manzana', 'banana', 'naranja'];
// Array con longitud fija (simulado)
const numerosFijos: number[] = new Array(3).fill(0);
// Operaciones
numeros.push(6);
numeros.unshift(0);
numeros.splice(1, 1);
// Métodos funcionales
const pares = numeros.filter(n => n % 2 === 0);
const duplicados = numeros.map(n => n * 2);
console.log('Números:', numeros);
console.log('Pares:', pares);
}
void ejemploMapas() {
// Map tipado
Map<String, int> edades = {
'Ana': 25,
'Luis': 30,
'María': 28
};
// Operaciones
edades['Carlos'] = 35;
edades.remove('Luis');
// Iteración
edades.forEach((nombre, edad) {
print('$nombre tiene $edad años');
});
// Métodos útiles
var nombres = edades.keys.toList();
var soloEdades = edades.values.toList();
var adultos = edades.entries
.where((entry) => entry.value >= 30)
.map((entry) => entry.key)
.toList();
}
function ejemploObjetos(): void {
// Objeto/Map tipado
const edades: Record<string, number> = {
'Ana': 25,
'Luis': 30,
'María': 28
};
// Usando Map nativo
const edadesMap = new Map<string, number>([
['Ana', 25],
['Luis', 30],
['María', 28]
]);
// Operaciones
edades['Carlos'] = 35;
delete edades['Luis'];
// Iteración
Object.entries(edades).forEach(([nombre, edad]) => {
console.log(`${nombre} tiene ${edad} años`);
});
// Métodos útiles
const nombres = Object.keys(edades);
const soloEdades = Object.values(edades);
const adultos = Object.entries(edades)
.filter(([, edad]) => edad >= 30)
.map(([nombre]) => nombre);
}
void ejemploSets() {
Set<String> colores = {'rojo', 'verde', 'azul'};
Set<int> numeros = {1, 2, 3, 3, 4}; // Automáticamente elimina duplicados
// Operaciones
colores.add('amarillo');
colores.addAll(['violeta', 'naranja']);
// Operaciones de conjuntos
Set<int> otrosNumeros = {3, 4, 5, 6};
var union = numeros.union(otrosNumeros);
var interseccion = numeros.intersection(otrosNumeros);
var diferencia = numeros.difference(otrosNumeros);
print('Unión: $union');
print('Intersección: $interseccion');
}
function ejemploSets(): void {
const colores = new Set<string>(['rojo', 'verde', 'azul']);
const numeros = new Set<number>([1, 2, 3, 3, 4]); // Elimina duplicados
// Operaciones
colores.add('amarillo');
['violeta', 'naranja'].forEach(color => colores.add(color));
// Operaciones de conjuntos
const otrosNumeros = new Set<number>([3, 4, 5, 6]);
const union = new Set([...numeros, ...otrosNumeros]);
const interseccion = new Set([...numeros].filter(x => otrosNumeros.has(x)));
const diferencia = new Set([...numeros].filter(x => !otrosNumeros.has(x)));
console.log('Unión:', union);
console.log('Intersección:', interseccion);
}
import 'dart:convert';
class Persona {
String nombre;
int edad;
List<String> hobbies;
Persona({required this.nombre, required this.edad, required this.hobbies});
// Serialización a JSON
Map<String, dynamic> toJson() {
return {
'nombre': nombre,
'edad': edad,
'hobbies': hobbies,
};
}
// Deserialización desde JSON
factory Persona.fromJson(Map<String, dynamic> json) {
return Persona(
nombre: json['nombre'] as String,
edad: json['edad'] as int,
hobbies: List<String>.from(json['hobbies']),
);
}
}
void ejemploSerializacion() {
var persona = Persona(
nombre: 'Ana',
edad: 25,
hobbies: ['lectura', 'programación']
);
// A JSON
String jsonString = jsonEncode(persona.toJson());
print('JSON: $jsonString');
// Desde JSON
Map<String, dynamic> jsonData = jsonDecode(jsonString);
var personaDeserializada = Persona.fromJson(jsonData);
print('Nombre: ${personaDeserializada.nombre}');
}
class Persona {
constructor(
public nombre: string,
public edad: number,
public hobbies: string[]
) {}
// Serialización a JSON (automática en TypeScript)
toJSON(): object {
return {
nombre: this.nombre,
edad: this.edad,
hobbies: this.hobbies
};
}
// Método estático para deserialización
static fromJSON(json: any): Persona {
return new Persona(
json.nombre,
json.edad,
json.hobbies
);
}
}
function ejemploSerializacion(): void {
const persona = new Persona('Ana', 25, ['lectura', 'programación']);
// A JSON
const jsonString = JSON.stringify(persona);
console.log('JSON:', jsonString);
// Desde JSON
const jsonData = JSON.parse(jsonString);
const personaDeserializada = Persona.fromJSON(jsonData);
console.log('Nombre:', personaDeserializada.nombre);
}
import 'dart:io';
import 'dart:convert';
Future<void> ejemploFicheros() async {
final archivo = File('datos.txt');
try {
// Escribir archivo
await archivo.writeAsString('Hola desde Dart\nSegunda línea');
// Leer archivo completo
String contenido = await archivo.readAsString();
print('Contenido: $contenido');
// Leer línea por línea
List<String> lineas = await archivo.readAsLines();
for (var i = 0; i < lineas.length; i++) {
print('Línea $i: ${lineas[i]}');
}
// Trabajar con JSON
var datos = {'nombre': 'Flutter', 'version': 3.0};
var archivoJson = File('datos.json');
await archivoJson.writeAsString(jsonEncode(datos));
// Leer JSON
String jsonContent = await archivoJson.readAsString();
Map<String, dynamic> datosLeidos = jsonDecode(jsonContent);
print('Datos JSON: $datosLeidos');
} catch (e) {
print('Error al manejar archivos: $e');
}
}
import { promises as fs } from 'fs';
import { readFileSync, writeFileSync } from 'fs';
async function ejemploFicheros(): Promise<void> {
const nombreArchivo = 'datos.txt';
try {
// Escribir archivo
await fs.writeFile(nombreArchivo, 'Hola desde TypeScript\nSegunda línea');
// Leer archivo completo
const contenido = await fs.readFile(nombreArchivo, 'utf8');
console.log('Contenido:', contenido);
// Leer línea por línea
const lineas = contenido.split('\n');
lineas.forEach((linea, i) => {
console.log(`Línea ${i}: ${linea}`);
});
// Trabajar con JSON
const datos = { nombre: 'Node.js', version: 18.0 };
await fs.writeFile('datos.json', JSON.stringify(datos, null, 2));
// Leer JSON
const jsonContent = await fs.readFile('datos.json', 'utf8');
const datosLeidos = JSON.parse(jsonContent);
console.log('Datos JSON:', datosLeidos);
} catch (error) {
console.error('Error al manejar archivos:', error);
}
}
import 'dart:async';
import 'dart:math';
Future<String> operacionAsincrona() async {
await Future.delayed(Duration(seconds: 2));
return 'Operación completada';
}
Future<int> calcularFactorial(int n) async {
if (n <= 1) return 1;
await Future.delayed(Duration(milliseconds: 100));
return n * await calcularFactorial(n - 1);
}
void ejemploFutures() async {
print('Iniciando operaciones...');
try {
// Future simple
String resultado = await operacionAsincrona();
print(resultado);
// Future con transformación
var futureNumero = Future.value(42);
var numeroTransformado = await futureNumero.then((valor) => valor * 2);
print('Número transformado: $numeroTransformado');
// Múltiples futures en paralelo
var futures = [
calcularFactorial(5),
calcularFactorial(4),
calcularFactorial(3)
];
List<int> resultados = await Future.wait(futures);
print('Factoriales: $resultados');
} catch (e) {
print('Error: $e');
}
}
function operacionAsincrona(): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Operación completada');
}, 2000);
});
}
async function calcularFactorial(n: number): Promise<number> {
if (n <= 1) return 1;
await new Promise(resolve => setTimeout(resolve, 100));
return n * await calcularFactorial(n - 1);
}
async function ejemploPromises(): Promise<void> {
console.log('Iniciando operaciones...');
try {
// Promise simple
const resultado = await operacionAsincrona();
console.log(resultado);
// Promise con transformación
const promiseNumero = Promise.resolve(42);
const numeroTransformado = await promiseNumero.then(valor => valor * 2);
console.log('Número transformado:', numeroTransformado);
// Múltiples promises en paralelo
const promises = [
calcularFactorial(5),
calcularFactorial(4),
calcularFactorial(3)
];
const resultados = await Promise.all(promises);
console.log('Factoriales:', resultados);
} catch (error) {
console.error('Error:', error);
}
}
import 'dart:async';
Stream<int> generarNumeros() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
Stream<String> procesarStream(Stream<int> input) async* {
await for (int numero in input) {
yield 'Procesado: $numero';
}
}
void ejemploStreams() async {
// Stream básico
var streamNumeros = generarNumeros();
await for (int numero in streamNumeros) {
print('Recibido: $numero');
}
// Stream con transformaciones
var streamProcesado = procesarStream(generarNumeros());
streamProcesado.listen(
(dato) => print(dato),
onError: (error) => print('Error: $error'),
onDone: () => print('Stream completado'),
);
}
class SimpleStream<T> {
private listeners: ((value: T) => void)[] = [];
subscribe(callback: (value: T) => void): void {
this.listeners.push(callback);
}
emit(value: T): void {
this.listeners.forEach(callback => callback(value));
}
}
async function* generarNumeros(): AsyncGenerator<number> {
for (let i = 1; i <= 5; i++) {
await new Promise(resolve => setTimeout(resolve, 1000));
yield i;
}
}
async function ejemploStreams(): Promise<void> {
// Usando generators
console.log('Iniciando stream...');
for await (const numero of generarNumeros()) {
console.log('Recibido:', numero);
}
// Simulando stream con eventos
const stream = new SimpleStream<string>();
stream.subscribe((dato) => console.log('Stream:', dato));
setTimeout(() => stream.emit('Primer mensaje'), 1000);
setTimeout(() => stream.emit('Segundo mensaje'), 2000);
}
// Excepciones personalizadas
class ErrorPersonalizado implements Exception {
final String mensaje;
ErrorPersonalizado(this.mensaje);
@override
String toString() => 'ErrorPersonalizado: $mensaje';
}
Future<double> dividir(double a, double b) async {
if (b == 0) {
throw ErrorPersonalizado('División por cero no permitida');
}
return a / b;
}
void ejemploControlErrores() async {
// Try-catch básico
try {
double resultado = await dividir(10, 2);
print('Resultado: $resultado');
// Esto lanzará una excepción
await dividir(10, 0);
} on ErrorPersonalizado catch (e) {
print('Error personalizado capturado: $e');
} catch (e, stackTrace) {
print('Error general: $e');
print('Stack trace: $stackTrace');
} finally {
print('Bloque finally ejecutado');
}
// Manejo con Result pattern
var resultado = await ejecutarSinExcepciones();
if (resultado.isSuccess) {
print('Éxito: ${resultado.value}');
} else {
print('Error: ${resultado.error}');
}
}
class Result<T> {
final T? value;
final String? error;
final bool isSuccess;
Result.success(this.value) : error = null, isSuccess = true;
Result.failure(this.error) : value = null, isSuccess = false;
}
Future<Result<String>> ejecutarSinExcepciones() async {
try {
await Future.delayed(Duration(milliseconds: 100));
return Result.success('Operación exitosa');
} catch (e) {
return Result.failure(e.toString());
}
}
// Errores personalizados
class ErrorPersonalizado extends Error {
constructor(mensaje: string) {
super(mensaje);
this.name = 'ErrorPersonalizado';
}
}
async function dividir(a: number, b: number): Promise<number> {
if (b === 0) {
throw new ErrorPersonalizado('División por cero no permitida');
}
return a / b;
}
async function ejemploControlErrores(): Promise<void> {
// Try-catch básico
try {
const resultado = await dividir(10, 2);
console.log('Resultado:', resultado);
// Esto lanzará una excepción
await dividir(10, 0);
} catch (error) {
if (error instanceof ErrorPersonalizado) {
console.log('Error personalizado capturado:', error.message);
} else {
console.log('Error general:', error);
console.log('Stack trace:', (error as Error).stack);
}
} finally {
console.log('Bloque finally ejecutado');
}
// Manejo con Result pattern
const resultado = await ejecutarSinExcepciones();
if (resultado.isSuccess) {
console.log('Éxito:', resultado.value);
} else {
console.log('Error:', resultado.error);
}
}
type Result<T> = {
value?: T;
error?: string;
isSuccess: boolean;
};
async function ejecutarSinExcepciones(): Promise<Result<string>> {
try {
await new Promise(resolve => setTimeout(resolve, 100));
return { value: 'Operación exitosa', isSuccess: true };
} catch (error) {
return { error: error instanceof Error ? error.message : String(error), isSuccess: false };
}
}
// Clase abstracta
abstract class Animal {
String nombre;
int edad;
Animal(this.nombre, this.edad);
// Método abstracto
void hacerSonido();
// Método concreto
void dormir() {
print('$nombre está durmiendo');
}
// Getter
String get info => '$nombre tiene $edad años';
}
// Interfaz (usando abstract class)
abstract class Volador {
void volar();
}
// Clase concreta con herencia
class Perro extends Animal {
String raza;
Perro(String nombre, int edad, this.raza) : super(nombre, edad);
@override
void hacerSonido() {
print('$nombre ladra: ¡Guau guau!');
}
void buscarPelota() {
print('$nombre está buscando la pelota');
}
}
// Clase con múltiples interfaces
class Pajaro extends Animal implements Volador {
double envergaduraAlas;
Pajaro(String nombre, int edad, this.envergaduraAlas) : super(nombre, edad);
@override
void hacerSonido() {
print('$nombre canta: ¡Pío pío!');
}
@override
void volar() {
print('$nombre vuela con sus alas de ${envergaduraAlas}cm');
}
}
// Mixins
mixin Nadador {
void nadar() {
print('Nadando en el agua');
}
}
class Pato extends Animal with Nadador implements Volador {
Pato(String nombre, int edad) : super(nombre, edad);
@override
void hacerSonido() {
print('$nombre hace: ¡Cuac cuac!');
}
@override
void volar() {
print('$nombre vuela sobre el agua');
}
}
void ejemploOOP() {
var perro = Perro('Rex', 3, 'Labrador');
var pajaro = Pajaro('Tweety', 1, 15.5);
var pato = Pato('Donald', 2);
List<Animal> animales = [perro, pajaro, pato];
for (var animal in animales) {
print(animal.info);
animal.hacerSonido();
animal.dormir();
if (animal is Volador) {
animal.volar();
}
if (animal is Nadador) {
animal.nadar();
}
print('---');
}
}
// Clase abstracta
abstract class Animal {
constructor(
protected nombre: string,
protected edad: number
) {}
// Método abstracto
abstract hacerSonido(): void;
// Método concreto
dormir(): void {
console.log(`${this.nombre} está durmiendo`);
}
// Getter
get info(): string {
return `${this.nombre} tiene ${this.edad} años`;
}
}
// Interfaz
interface Volador {
volar(): void;
}
// Clase concreta con herencia
class Perro extends Animal {
constructor(nombre: string, edad: number, private raza: string) {
super(nombre, edad);
}
hacerSonido(): void {
console.log(`${this.nombre} ladra: ¡Guau guau!`);
}
buscarPelota(): void {
console.log(`${this.nombre} está buscando la pelota`);
}
}
// Clase con interfaz
class Pajaro extends Animal implements Volador {
constructor(
nombre: string,
edad: number,
private envergaduraAlas: number
) {
super(nombre, edad);
}
hacerSonido(): void {
console.log(`${this.nombre} canta: ¡Pío pío!`);
}
volar(): void {
console.log(`${this.nombre} vuela con sus alas de ${this.envergaduraAlas}cm`);
}
}
// Mixins simulation with composition
class MixinNadador {
nadar(): void {
console.log('Nadando en el agua');
}
}
class Pato extends Animal implements Volador {
private nadadorMixin = new MixinNadador();
constructor(nombre: string, edad: number) {
super(nombre, edad);
}
hacerSonido(): void {
console.log(`${this.nombre} hace: ¡Cuac cuac!`);
}
volar(): void {
console.log(`${this.nombre} vuela sobre el agua`);
}
nadar(): void {
this.nadadorMixin.nadar();
}
}
function ejemploOOP(): void {
const perro = new Perro('Rex', 3, 'Labrador');
const pajaro = new Pajaro('Tweety', 1, 15.5);
const pato = new Pato('Donald', 2);
const animales: Animal[] = [perro, pajaro, pato];
animales.forEach(animal => {
console.log(animal.info);
animal.hacerSonido();
animal.dormir();
// Type checking
if ('volar' in animal) {
(animal as Volador).volar();
}
if ('nadar' in animal) {
(animal as any).nadar();
}
console.log('---');
});
}
void ejemploLambdas() {
// Funciones lambda básicas
var sumar = (int a, int b) => a + b;
var multiplicar = (int a, int b) {
return a * b;
};
print('Suma: ${sumar(5, 3)}');
print('Multiplicación: ${multiplicar(4, 6)}');
// Con listas
List<int> numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Map
var cuadrados = numeros.map((n) => n * n).toList();
var cubos = numeros.map((numero) {
return numero * numero * numero;
}).toList();
// Filter
var pares = numeros.where((n) => n % 2 == 0).toList();
var mayoresA5 = numeros.where((numero) => numero > 5).toList();
// Reduce
var suma = numeros.reduce((a, b) => a + b);
var producto = numeros.fold<int>(1, (prev, element) => prev * element);
// Sort
List<String> nombres = ['Ana', 'Carlos', 'Beatriz', 'Daniel'];
nombres.sort((a, b) => a.compareTo(b));
print('Cuadrados: $cuadrados');
print('Números pares: $pares');
print('Suma total: $suma');
print('Nombres ordenados: $nombres');
// Funciones de orden superior
ejecutarOperacion(10, 5, (a, b) => a + b);
ejecutarOperacion(10, 5, (a, b) => a - b);
// Closures
var contador = crearContador();
print('Contador: ${contador()}'); // 1
print('Contador: ${contador()}'); // 2
print('Contador: ${contador()}'); // 3
// Función que retorna función
var multiplicadorPor3 = crearMultiplicador(3);
print('5 * 3 = ${multiplicadorPor3(5)}');
}
void ejecutarOperacion(int a, int b, int Function(int, int) operacion) {
var resultado = operacion(a, b);
print('Resultado de la operación: $resultado');
}
Function crearContador() {
int count = 0;
return () => ++count;
}
Function(int) crearMultiplicador(int factor) {
return (int numero) => numero * factor;
}
function ejemploLambdas(): void {
// Funciones lambda básicas
const sumar = (a: number, b: number) => a + b;
const multiplicar = (a: number, b: number) => {
return a * b;
};
console.log('Suma:', sumar(5, 3));
console.log('Multiplicación:', multiplicar(4, 6));
// Con arrays
const numeros: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Map
const cuadrados = numeros.map(n => n * n);
const cubos = numeros.map(numero => {
return numero * numero * numero;
});
// Filter
const pares = numeros.filter(n => n % 2 === 0);
const mayoresA5 = numeros.filter(numero => numero > 5);
// Reduce
const suma = numeros.reduce((a, b) => a + b, 0);
const producto = numeros.reduce((prev, element) => prev * element, 1);
// Sort
const nombres: string[] = ['Ana', 'Carlos', 'Beatriz', 'Daniel'];
nombres.sort((a, b) => a.localeCompare(b));
console.log('Cuadrados:', cuadrados);
console.log('Números pares:', pares);
console.log('Suma total:', suma);
console.log('Nombres ordenados:', nombres);
// Funciones de orden superior
ejecutarOperacion(10, 5, (a, b) => a + b);
ejecutarOperacion(10, 5, (a, b) => a - b);
// Closures
const contador = crearContador();
console.log('Contador:', contador()); // 1
console.log('Contador:', contador()); // 2
console.log('Contador:', contador()); // 3
// Función que retorna función
const multiplicadorPor3 = crearMultiplicador(3);
console.log('5 * 3 =', multiplicadorPor3(5));
}
function ejecutarOperacion(a: number, b: number, operacion: (a: number, b: number) => number): void {
const resultado = operacion(a, b);
console.log('Resultado de la operación:', resultado);
}
function crearContador(): () => number {
let count = 0;
return () => ++count;
}
function crearMultiplicador(factor: number): (numero: number) => number {
return (numero: number) => numero * factor;
}
// Clase genérica
class Caja<T> {
T _contenido;
Caja(this._contenido);
T get contenido => _contenido;
set contenido(T valor) => _contenido = valor;
void mostrar() {
print('Contenido: $_contenido (${_contenido.runtimeType})');
}
}
// Función genérica
T intercambiar<T>(T valor1, T valor2, bool condicion) {
return condicion ? valor1 : valor2;
}
// Lista genérica personalizada
class MiLista<T> {
List<T> _items = [];
void agregar(T item) => _items.add(item);
T? obtener(int indice) => indice < _items.length ? _items[indice] : null;
int get longitud => _items.length;
List<U> mapear<U>(U Function(T) transformador) {
return _items.map(transformador).toList();
}
}
void ejemploGenerics() {
// Usando la clase genérica
var cajaString = Caja<String>('Hola Dart');
var cajaInt = Caja<int>(42);
cajaString.mostrar();
cajaInt.mostrar();
// Función genérica
var resultado = intercambiar<String>('A', 'B', true);
print('Intercambio: $resultado');
// Lista personalizada
var miLista = MiLista<int>();
miLista.agregar(1);
miLista.agregar(2);
miLista.agregar(3);
var strings = miLista.mapear<String>((n) => 'Número: $n');
print('Strings: $strings');
}
// Clase genérica
class Caja<T> {
private _contenido: T;
constructor(contenido: T) {
this._contenido = contenido;
}
get contenido(): T {
return this._contenido;
}
set contenido(valor: T) {
this._contenido = valor;
}
mostrar(): void {
console.log(`Contenido: ${this._contenido} (${typeof this._contenido})`);
}
}
// Función genérica
function intercambiar<T>(valor1: T, valor2: T, condicion: boolean): T {
return condicion ? valor1 : valor2;
}
// Lista genérica personalizada
class MiLista<T> {
private _items: T[] = [];
agregar(item: T): void {
this._items.push(item);
}
obtener(indice: number): T | undefined {
return indice < this._items.length ? this._items[indice] : undefined;
}
get longitud(): number {
return this._items.length;
}
mapear<U>(transformador: (item: T) => U): U[] {
return this._items.map(transformador);
}
}
function ejemploGenerics(): void {
// Usando la clase genérica
const cajaString = new Caja<string>('Hola TypeScript');
const cajaInt = new Caja<number>(42);
cajaString.mostrar();
cajaInt.mostrar();
// Función genérica
const resultado = intercambiar<string>('A', 'B', true);
console.log('Intercambio:', resultado);
// Lista personalizada
const miLista = new MiLista<number>();
miLista.agregar(1);
miLista.agregar(2);
miLista.agregar(3);
const strings = miLista.mapear<string>(n => `Número: ${n}`);
console.log('Strings:', strings);
}
// Extensions en Dart
extension StringExtensions on String {
bool get esVacio => isEmpty;
bool get noEsVacio => isNotEmpty;
String capitalizar() {
if (isEmpty) return this;
return this[0].toUpperCase() + substring(1).toLowerCase();
}
String invertir() {
return split('').reversed.join('');
}
bool esPalindromo() {
var limpio = replaceAll(RegExp(r'[^a-zA-Z0-9]'), '').toLowerCase();
return limpio == limpio.split('').reversed.join('');
}
}
extension ListExtensions<T> on List<T> {
T? get primero => isEmpty ? null : first;
T? get ultimo => isEmpty ? null : last;
List<T> shuffle() {
var nueva = List<T>.from(this);
nueva.shuffle();
return nueva;
}
Map<K, List<T>> agruparPor<K>(K Function(T) selector) {
var mapa = <K, List<T>>{};
for (var item in this) {
var clave = selector(item);
mapa.putIfAbsent(clave, () => []).add(item);
}
return mapa;
}
}
void ejemploExtensions() {
// String extensions
String texto = 'hola mundo';
print('Capitalizado: ${texto.capitalizar()}');
print('Invertido: ${texto.invertir()}');
print('¿Es palíndromo "radar"? ${'radar'.esPalindromo()}');
// List extensions
List<int> numeros = [1, 2, 3, 4, 5];
print('Primer elemento: ${numeros.primero}');
print('Lista mezclada: ${numeros.shuffle()}');
List<String> palabras = ['casa', 'carro', 'computadora', 'celular'];
var agrupadas = palabras.agruparPor<String>((p) => p[0]);
print('Agrupadas por primera letra: $agrupadas');
}
// TypeScript no tiene extensions nativas, pero se pueden simular con declaration merging
declare global {
interface String {
esVacio(): boolean;
noEsVacio(): boolean;
capitalizar(): string;
invertir(): string;
esPalindromo(): boolean;
}
interface Array<T> {
primero(): T | undefined;
ultimo(): T | undefined;
shuffle(): T[];
agruparPor<K>(selector: (item: T) => K): Map<K, T[]>;
}
}
// Implementación de las extensiones
String.prototype.esVacio = function(): boolean {
return this.length === 0;
};
String.prototype.noEsVacio = function(): boolean {
return this.length > 0;
};
String.prototype.capitalizar = function(): string {
if (this.length === 0) return this.toString();
return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
};
String.prototype.invertir = function(): string {
return this.split('').reverse().join('');
};
String.prototype.esPalindromo = function(): boolean {
const limpio = this.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
return limpio === limpio.split('').reverse().join('');
};
Array.prototype.primero = function<T>(this: T[]): T | undefined {
return this.length > 0 ? this[0] : undefined;
};
Array.prototype.ultimo = function<T>(this: T[]): T | undefined {
return this.length > 0 ? this[this.length - 1] : undefined;
};
Array.prototype.shuffle = function<T>(this: T[]): T[] {
const nueva = [...this];
for (let i = nueva.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[nueva[i], nueva[j]] = [nueva[j], nueva[i]];
}
return nueva;
};
Array.prototype.agruparPor = function<T, K>(this: T[], selector: (item: T) => K): Map<K, T[]> {
const mapa = new Map<K, T[]>();
for (const item of this) {
const clave = selector(item);
if (!mapa.has(clave)) {
mapa.set(clave, []);
}
mapa.get(clave)!.push(item);
}
return mapa;
};
function ejemploExtensions(): void {
// String extensions
const texto = 'hola mundo';
console.log('Capitalizado:', texto.capitalizar());
console.log('Invertido:', texto.invertir());
console.log('¿Es palíndromo "radar"?', 'radar'.esPalindromo());
// Array extensions
const numeros = [1, 2, 3, 4, 5];
console.log('Primer elemento:', numeros.primero());
console.log('Lista mezclada:', numeros.shuffle());
const palabras = ['casa', 'carro', 'computadora', 'celular'];
const agrupadas = palabras.agruparPor(p => p[0]);
console.log('Agrupadas por primera letra:', agrupadas);
}
Característica | Dart | TypeScript |
---|---|---|
Tipado | Fuertemente tipado, inferencia | Tipado estático opcional |
Null Safety | Null safety nativo | Strict null checks |
Compilación | AOT/JIT a código nativo | Transpila a JavaScript |
Plataformas | Mobile, Web, Desktop, Server | Web, Node.js, Desktop |
Sintaxis | Similar a Java/C# | Superset de JavaScript |
Async/Await | Future/Stream nativos | Promise/async-await |
Orientación a Objetos | Clases, mixins, interfaces | Clases, interfaces |
Funcional | Funciones de primera clase | Funciones de primera clase |
Extensions | Extensions nativas | Declaration merging |
Generics | Soporte completo | Soporte completo |
Ecosistema | pub.dev | npm |
- Rendimiento: Compilación AOT para mejor rendimiento
- Flutter: Desarrollo multiplataforma nativo
- Null Safety: Incorporado por defecto
- Hot Reload: Desarrollo rápido
- Sintaxis limpia: Menos verboso que TypeScript
- Mixins: Composición más flexible
- Ecosistema: Acceso a todo el ecosistema JavaScript
- Gradual: Adopción incremental en proyectos JS
- Herramientas: Mejor soporte de IDEs
- Comunidad: Más grande y madura
- Flexibilidad: Más opciones de configuración
- Interoperabilidad: Funciona con librerías JS existentes
- Desarrollas aplicaciones móviles con Flutter
- Necesitas aplicaciones de alto rendimiento
- Quieres una sola base de código para múltiples plataformas
- Prefieres un lenguaje más estructurado y menos permisivo
- El null safety es crítico en tu aplicación
- Desarrollas aplicaciones web
- Tienes un equipo con experiencia en JavaScript
- Necesitas integrar con librerías JavaScript existentes
- Quieres migrar gradualmente desde JavaScript
- Desarrollas aplicaciones Node.js
Tanto Dart como TypeScript son lenguajes modernos y potentes, cada uno con sus fortalezas específicas. Dart brilla en el desarrollo móvil multiplataforma con Flutter, mientras que TypeScript es excelente para desarrollo web y aplicaciones Node.js. La elección entre ellos depende principalmente del tipo de aplicación que estés desarrollando y del ecosistema en el que prefieras trabajar.
Ambos lenguajes ofrecen características modernas como tipado fuerte, programación asíncrona, orientación a objetos, y programación funcional, lo que los hace opciones sólidas para el desarrollo de aplicaciones modernas.