TypeScript

Equivalencias idiomáticas entre Kotlin y TypeScript. Kotlin se presenta como referencia en cada concepto.

Integración con el ecosistema

Un algoritmo correcto también debe compilarse, organizarse y ejecutarse: estas herramientas son las que hacen posible entregar y comparar una implementación real.

Equivalencia desde Kotlin

Herramientas

Cercana

En TypeScript, Bun (bun install, bun run, bunfig.toml) permite implementar este comportamiento: Instala las dependencias declaradas, construye todos los módulos, ejecuta las pruebas y corre la aplicación de línea de comandos.

Referencia Kotlin: Gradle, mediante el wrapper ./gradlew, resuelve las dependencias declaradas, construye los subproyectos registrados en settings.gradle.kts y ejecuta tareas como build, test y :app:run.

Mecanismo
Bun (bun install, bun run, bunfig.toml)
Riesgo de diseño
Confundir la forma de Bun (bun install, bun run, bunfig.toml) con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica Bun (bun install, bun run, bunfig.toml) solo a la garantía que proporciona.

Diferencias relevantes

  • Distingue el ejecutable de build invocado (el wrapper o la CLI de la herramienta) de los archivos de manifiesto y lockfile que declaran las dependencias y su resolución.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Instala las dependencias declaradas, construye todos los módulos, ejecuta las pruebas y corre la aplicación de línea de comandos.

docker compose run --rm app bun install
docker compose run --rm app bun test
docker compose run --rm app bun run start

Dockerfile mínimo para el toolchain de TypeScript.

FROM oven/bun:1
WORKDIR /workspace
COPY . .

compose.yaml: construye la imagen y monta el proyecto para correr los comandos anteriores dentro del contenedor.

services:
  app:
    build: .
    volumes:
      - .:/workspace
    working_dir: /workspace

Fuentes

Equivalencia desde Kotlin

Módulos, workspaces y monorepos

Cercana

En TypeScript, workspaces de Bun ("workspaces": ["packages/*"] en el package.json raíz) permite implementar este comportamiento: Organiza un ejecutable de línea de comandos que depende de módulos de dominio reutilizables, conservando el sentido de la dependencia.

Referencia Kotlin: Un build multi-proyecto de Gradle declara sus subproyectos (:app, :optimization:core, :optimization:execution, :optimization:baselines, :optimization:metaheuristics:single-state, :reporting:fair) en settings.gradle.kts mediante include(...), mientras que la lógica de build compartida vive en builds incluidos aparte (build-logic, build-conventions) declarados con includeBuild(...); cada dependencia entre proyectos se declara explícitamente, por ejemplo implementation(projects.optimization.core) en el build.gradle.kts de :app.

Mecanismo
workspaces de Bun ("workspaces": ["packages/*"] en el package.json raíz)
Riesgo de diseño
Confundir la forma de workspaces de Bun ("workspaces": ["packages/*"] en el package.json raíz) con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica workspaces de Bun ("workspaces": ["packages/*"] en el package.json raíz) solo a la garantía que proporciona.

Diferencias relevantes

  • Un monorepo es una estrategia de alojamiento de un repositorio, no un mecanismo de build: un repositorio puede ser un monorepo sin usar ningún workspace, y un workspace puede vivir en un repositorio que no aloja ningún otro proyecto además del suyo.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Organiza un ejecutable de línea de comandos que depende de módulos de dominio reutilizables, conservando el sentido de la dependencia.

// package.json (raíz)
{ "workspaces": ["packages/*"] }

// packages/cli/package.json
{ "dependencies": { "@atom/core": "workspace:*" } }

Fuentes

Equivalencia desde Kotlin

Soporte CLI

Cercana

En TypeScript, oclif, con una clase por comando y sus flags tipados permite implementar este comportamiento: Ejecuta random-search con un archivo de configuración y escribe su reporte, mostrando ayuda generada y fallando antes de optimizar ante una opción inválida.

Referencia Kotlin: Clikt define atom como comando raíz sin operación propia (NoOpCliktCommand) con los subcomandos random-search y local-search; cada uno extiende AbstractExperimentCommand, que declara --config y --report como opciones requeridas y --report-format con v4 por defecto, valida la configuración antes de ejecutar el experimento y traduce los errores esperados en CliktError.

Mecanismo
oclif, con una clase por comando y sus flags tipados
Riesgo de diseño
Confundir la forma de oclif, con una clase por comando y sus flags tipados con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica oclif, con una clase por comando y sus flags tipados solo a la garantía que proporciona.

Diferencias relevantes

  • El análisis de argumentos y su validación deben completarse antes de ejecutar cualquier lógica de optimización; ninguna biblioteca madura y con pruebas propias debe reemplazarse por un analizador manual.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Ejecuta random-search con un archivo de configuración y escribe su reporte, mostrando ayuda generada y fallando antes de optimizar ante una opción inválida.

export default class RandomSearch extends Command {
    static flags = {
        config: Flags.string({ required: true }),
        report: Flags.string({ required: true }),
        reportFormat: Flags.string({ default: "v4" }),
    };

    async run() {
        const { flags } = await this.parse(RandomSearch);
        // decodifica, ejecuta y escribe el reporte
    }
}

Contrato observable compartido por cualquier reimplementación de la CLI.

$ atom random-search --config config.json --report report.json
Completed random-search: 2 runs; report format: v4; report: report.json

Fuentes

Equivalencia desde Kotlin

Serialización

Cercana

En TypeScript, Zod (z.object({...}) con schema.parse o schema.safeParse) permite implementar este comportamiento: Decodifica una configuración JSON con el objetivo, las semillas y el valor objetivo opcional de un experimento, distinguiendo un JSON sintácticamente inválido de un valor de dominio inválido.

Referencia Kotlin: kotlinx.serialization decodifica el JSON tipado mediante un Json compartido (prettyPrint = true, encodeDefaults = true) y un SerializersModule polimórfico para tipos como SearchSpace; readFromJson<T>() decodifica el archivo y deja que SerializationException se propague, mientras que un valor de dominio inválido, como un Delta no positivo, falla por separado en el constructor de su clase de valor.

Mecanismo
Zod (z.object({...}) con schema.parse o schema.safeParse)
Riesgo de diseño
Confundir la forma de Zod (z.object({...}) con schema.parse o schema.safeParse) con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica Zod (z.object({...}) con schema.parse o schema.safeParse) solo a la garantía que proporciona.

Diferencias relevantes

  • Un JSON sintácticamente válido puede seguir violando un invariante de dominio; decodificar con éxito no implica que el valor resultante sea válido.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Decodifica una configuración JSON con el objetivo, las semillas y el valor objetivo opcional de un experimento, distinguiendo un JSON sintácticamente inválido de un valor de dominio inválido.

const ExperimentConfig = z.object({
    objective: z.string(),
    seeds: z.array(z.number().int()),
    targetValue: z.number().default(0),
});
const config = ExperimentConfig.parse(JSON.parse(json));

Payload compartido: seeds es requerido; targetValue es opcional y por defecto 0.0.

{
  "objective": "sphere",
  "seeds": [7, 11],
  "targetValue": 0.0
}

Fuentes

Ecosistemas de pruebas

Verificar el comportamiento de una implementación requiere elegir, entre varias estrategias, la que responde mejor a cada tipo de afirmación sobre el algoritmo.

Equivalencia desde Kotlin

Desarrollo guiado por pruebas (TDD)

Cercana

Formula primero el comportamiento con Given–When–Then. En rojo, ejecuta el test más pequeño que demuestra que falta; en verde, implementa solo lo necesario; al refactorizar, mejora el diseño sin cambiar el comportamiento. Repite el ciclo con la siguiente afirmación. BDD puede ayudar a descubrir o expresar el comportamiento, pero Gherkin y los nombres legibles no son requisitos de TDD.

Referencia Kotlin: TDD parte por una afirmación observable y usa el test para conducir un cambio pequeño.

Mecanismo
bun:test con test y expect(...).toThrow
Riesgo de diseño
Escribir una prueba grande que atraviesa configuración, red o archivos antes de haber fijado una sola regla observable.
Recomendación
Elige una afirmación pequeña, ejecútala en rojo, hazla verde con el cambio mínimo y refactoriza solo mientras permanezca verde.

Diferencias relevantes

  • El ciclo rojo–verde–refactor se conserva entre ecosistemas; cambian el runner, la sintaxis de aserciones y la forma de expresar una excepción.
  • El test debe fallar por el comportamiento ausente, no por una dependencia, una ruta o una integración todavía no necesaria.

Un presupuesto de evaluación positivo se acepta y uno no positivo se rechaza.

import { expect, test } from "bun:test";

test("rejects a non-positive budget", () => {
    expect(() => Budget.of(0)).toThrow(RangeError);
});

Fuentes

Equivalencia desde Kotlin

Selección de estrategia de pruebas

Cercana

Empieza por la afirmación: usa un ejemplo enfocado para un comportamiento conocido, DDT para una matriz finita y PBT para una ley general. Añade pruebas de componente o integración cuando colaboran módulos, pruebas de contrato para una representación compartida y una verificación de entrega cuando importa el entorno documentado. Para algoritmos estocásticos controla colaboradores, conserva semillas reproducibles y prueba invariantes o evidencia estadística, no una trayectoria casual.

Referencia Kotlin: Seleccionar pruebas parte de la afirmación, la frontera afectada y las dependencias que deben controlarse.

Mecanismo
bun:test y Bun para pruebas enfocadas, DDT y ejecución del proyecto
Riesgo de diseño
Usar una prueba end-to-end para demostrar una regla local, o adoptar PBT solo porque hay un generador disponible.
Recomendación
Elige la evidencia más pequeña que pueda observar y falsar la afirmación; amplíala solo cuando una frontera modificada lo requiera.

Diferencias relevantes

  • La selección depende de la afirmación y la frontera, no del lenguaje ni del tamaño de una función.
  • Una prueba más amplia complementa la evidencia enfocada de TDD; no la reemplaza.

La afirmación determina la evidencia más pequeña adecuada antes de ampliar la verificación.

// Regla conocida: test(...).
expect(() => Budget.of(0)).toThrow();
// Matriz finita: test.each(...).
// Ley general: fc.property(...) con fast-check.

Fuentes

Equivalencia desde Kotlin

Pruebas unitarias

Cercana

En TypeScript, bun:test con test, expect y bun test permite implementar este comportamiento: Acepta el presupuesto 1000 y rechaza el presupuesto -1 antes de ejecutar optimización.

Referencia Kotlin: Una prueba unitaria llama al analizador de presupuesto y compara el valor o el error de validación.

Mecanismo
bun:test con test, expect y bun test
Riesgo de diseño
Confundir la forma de bun:test con test, expect y bun test con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica bun:test con test, expect y bun test solo a la garantía que proporciona.

Diferencias relevantes

  • La prueba mantiene el análisis local: no inicia una ejecución de optimización ni un proceso externo.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Acepta el presupuesto 1000 y rechaza el presupuesto -1 antes de ejecutar optimización.

import { expect, test } from "bun:test";

test("rejects a negative budget", () => {
    expect(() => parseBudget("-1")).toThrow();
});

Fuentes

Equivalencia desde Kotlin

Frameworks y estilos BDD

Cercana

En TypeScript, Cucumber.js con archivos .feature y definiciones de pasos permite implementar este comportamiento: Describe que atom random-search --objective sphere --budget 1000 --seed 11 produce una configuración válida sin ejecutar optimización.

Referencia Kotlin: Un escenario describe la configuración observable; analizar el comando no ejecuta el algoritmo.

Mecanismo
Cucumber.js con archivos .feature y definiciones de pasos
Riesgo de diseño
Confundir la forma de Cucumber.js con archivos .feature y definiciones de pasos con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica Cucumber.js con archivos .feature y definiciones de pasos solo a la garantía que proporciona.

Diferencias relevantes

  • BDD comunica comportamiento y colaboración; un nombre de prueba legible por sí solo no crea un flujo de especificación completo.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Describe que atom random-search --objective sphere --budget 1000 --seed 11 produce una configuración válida sin ejecutar optimización.

Given("a budget of {int} evaluations", function (budget: number) {
  this.args = ["--budget", String(budget)];
});
Then("a valid experiment configuration is produced", function () {
  expect(parse(this.args)).toBeDefined();
});

Fuentes

Equivalencia desde Kotlin

Soporte DDT

Cercana

En TypeScript, test.each de Bun permite implementar este comportamiento: Una tabla cubre presupuesto válido, faltante, negativo, objetivo desconocido, semilla repetida y opción desconocida.

Referencia Kotlin: Los casos explícitos vinculan argumentos CLI con un resultado de análisis esperado.

Mecanismo
test.each de Bun
Riesgo de diseño
Confundir la forma de test.each de Bun con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica test.each de Bun solo a la garantía que proporciona.

Diferencias relevantes

  • DDT enumera ejemplos elegidos; no sustituye la generación de dominios ni una especificación de comportamiento.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Una tabla cubre presupuesto válido, faltante, negativo, objetivo desconocido, semilla repetida y opción desconocida.

test.each([["1000", true], ["-1", false]])(
  "budget %s is valid: %s",
  (value, valid) => expect(parseBudget(value).ok).toBe(valid),
);

Fuentes

Equivalencia desde Kotlin

Soporte PBT

Cercana

En TypeScript, fast-check ejecutado desde bun:test permite implementar este comportamiento: Para cualquier texto decimal positivo aceptado, el presupuesto resultante es positivo; los casos inválidos se reducen y se pueden reproducir.

Referencia Kotlin: Una propiedad general se ejecuta sobre valores generados y comunica cómo repetir un contraejemplo.

Mecanismo
fast-check ejecutado desde bun:test
Riesgo de diseño
Confundir la forma de fast-check ejecutado desde bun:test con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica fast-check ejecutado desde bun:test solo a la garantía que proporciona.

Diferencias relevantes

  • PBT genera y reduce datos; una matriz DDT conserva mejor los ejemplos que el lector debe reconocer directamente.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Para cualquier texto decimal positivo aceptado, el presupuesto resultante es positivo; los casos inválidos se reducen y se pueden reproducir.

test("positive budgets remain positive", () => {
  fc.assert(fc.property(fc.integer({ min: 1 }), (budget) =>
    expect(parseBudget(String(budget)).value).toBeGreaterThan(0)));
});

Fuentes

Equivalencia desde Kotlin

DSLs de aserciones

Cercana

En TypeScript, expect incluido en bun:test permite implementar este comportamiento: Una configuración analizada contiene objective = sphere, budget = 1000 y seeds = [11]; una falla debe identificar esperado y recibido.

Referencia Kotlin: Las aserciones expresan el resultado observable de una configuración sin ocultar su estructura relevante.

Mecanismo
expect incluido en bun:test
Riesgo de diseño
Confundir la forma de expect incluido en bun:test con una garantía que TypeScript no ofrece en tiempo de ejecución.
Recomendación
Declara el contrato observable y aplica expect incluido en bun:test solo a la garantía que proporciona.

Diferencias relevantes

  • Una biblioteca fluida puede mejorar el diagnóstico, pero no reemplaza una expectativa precisa ni es necesaria cuando la API idiomática ya basta.
  • La comprobación estática guía el diseño, pero el programa conserva la semántica de JavaScript al ejecutarse.

Una configuración analizada contiene objective = sphere, budget = 1000 y seeds = [11]; una falla debe identificar esperado y recibido.

expect(config).toEqual({ objective: "sphere", budget: 1000, seeds: [11] });

Fuentes