Por qué nulo importa más de lo que piensas

En este artículo, comparto ideas desde una perspectiva centrada en TypeScript. Para aquellos que todavía están arraigados en JavaScript. ¿Estás siquiera en 2024? Aunque los principios de esta guía no solo son aplicables a TypeScript/JavaScript, son convenciones para crear código más sólido y fácil de mantener en todos los marcos y lenguajes.

Habiendo trabajado con TypeScript durante muchos años, me he vuelto cada vez más atento a los matices que afectan la calidad del código. Una enseñanza común cuando aprendes JavaScript/TypeScript por primera vez de tu gurú de elección es representar valores vacíos con cadenas vacías. Muchos desarrolladores, incluidos aquellos con los que he colaborado, siguen esta práctica.

Creo que este enfoque defectuoso puede provocar un comportamiento impredecible y no determinista en su código. Aquí es donde el uso adecuado de null e undefined se vuelve crucial.

Considere el siguiente ejemplo, donde tenemos una función diseñada para recuperar un avatar. Si se proporciona un nombre, la función usa DiceBear (felicitaciones a @Friosn por informarme sobre esta biblioteca) para generar una representación de cadena SVG. Sin embargo, el punto central de esta discusión es la segunda declaración de devolución de la función. A primera vista, puede parecer lógico devolver una cadena vacía cuando no hay ningún avatar disponible, pero ese no es el enfoque ideal.

 
import { lorelei } from '@dicebear/collection';

 function getAvatar(name: string | null) : string {
 if (name) {
 const avatar = createAvatar(lorelei, { seed: name });
 return avatar.toString();
 }

 return "";
 } 
Un tipo de devolución más apropiado en este escenario es nulo. La función revisada se vería así:
 
import { lorelei } from '@dicebear/collection';

 function getAvatar(name: string | null) : string | null {
 if (name) {
 const avatar = createAvatar(lorelei, { seed: name });
 return avatar.toString();
 }

 return null;
 }

Al devolver nulo, indicamos explícitamente: "Intentamos devolver un avatar, pero como no está disponible, devolvemos una representación de 'sin valor'".

Anular o no anular

Esta distinción es crucial por varias razones:

  1. Claridad semántica : la claridad en la codificación es primordial. Una cadena vacía ( "" ) y null transmiten significados distintos. Una cadena vacía es un tipo de cadena, aunque sin caracteres, mientras que null representa la ausencia total de un valor. En la función getAvatar , devolver null indica claramente la indisponibilidad de un avatar, evitando confusión con un avatar potencialmente válido pero vacío.
  2. Seguridad de tipos : la fortaleza de TypeScript radica en su seguridad de tipos. Permitir null como tipo de retorno permite una verificación de tipos más estricta, lo que reduce la probabilidad de errores en los que se usa incorrectamente una cadena vacía en lugar de un valor de cadena legítimo. Esta claridad beneficia tanto al compilador como a otros desarrolladores que leen su código.
  3. Manejo de errores y depuración : el manejo de errores y la depuración se vuelven más sencillos usando null . Indica la ausencia de un valor, lo que facilita la implementación de rutinas específicas de manejo de errores o la identificación de problemas durante la depuración. Por el contrario, es posible que una cadena vacía no indique inmediatamente un estado de error, lo que genera errores más difíciles de detectar.
  4. Diseño y expectativas de API : las expectativas claras son cruciales al diseñar API. Al utilizar null para indicar que no hay valor, establece una expectativa clara para los usuarios de API: deben anticipar una cadena válida o un valor nulo, no una cadena vacía pseudoválida. Esto agrega una capa adicional de validez a su código, aprovechando los tipos de manera efectiva.

Considere las variables como vasos: null es similar a un vaso vacío, lo que indica su vacío. Una string vacía, sin embargo, es como un vaso con la etiqueta String pero vacío por dentro, lo que genera una falta de coincidencia entre la representación del tipo y el contenido real, lo que afecta negativamente el comportamiento del código.

Es como ir a un café y pedir un vaso de limonada, sólo para que le den un vaso vacío y le digan: "Aquí tienes tu vaso de limonada". La implementación de la primera versión de getAvatar es similar a este escenario. Con la firma getAvatar(name: string): string , no hay ninguna opción para manejar los casos en los que no se encuentra limonada. En cambio, pides limonada y recibes un vaso vacío.

Pides limonada y recibes un vaso vacío.

Cadena nula/vacía representada como gafas.



Una nota sobre lo indefinido

Respecto a undefinido , i significa la ausencia total de un valor. Como regla general, evite devolver undefinido explícitamente. undefinido debe reservarse para situaciones en las que no existe una referencia a un valor. Por ejemplo:

 
 const myVar = undefined;

Aquí, nulo significa un valor vacío, mientras que indefinido significa inexistencia. Para hacer una analogía, considere indefinido como no tener un vaso, mientras que nulo representa un vaso vacío.

Indefinido/Nulo como vasos inexistentes y vacíos.

Al implementar estos cambios sutiles pero impactantes, puede mejorar la capacidad de mantenimiento de su código con definiciones de tipos más estrictas, logrando un código más limpio y determinista.

Regresar al blog

Deja un comentario