typescript - ¿Hay una mejor manera de agregar undefined y null a un tipo que crear tu propio genérico?
Es bastante común tener métodos donde uno o más parámetros pueden ser null o undefined (o a menudo ambos con tipos derivados). Esto puede resultar en firmas de métodos realmente largas en algunos casos:
doThing(
user: User | undefined | null,
thing: Thing | undefined | null,
...moreArgs
): Result {
// ...
}
Soy consciente de algunas formas de intentar resolver este problema, pero ambas tienen desventajas.
Los parámetros opcionales son excelentes si el argumento es realmente opcional, pero se sienten incómodos cuando el objeto pasado puede ser null.
Esto es más corto pero simplemente me parece incorrecto:
doThing(user?: User | null, thing?: Thing | null, ...moreArgs)
La otra manera que conozco para arreglar esto es con un genérico:
type Nullable<T> = T | null | undefined
doThing(user: Nullable<User>, thing: Nullable<Thing>)
Esto es razonable, pero encuentro que los proyectos a menudo terminan con más de un genérico de este tipo definido, se importan desde bibliotecas de terceros, los tipos derivados terminan teniendo una cadena de Maybe<T>, Nullable<T>, etc. Tratar de mantener este uso estándar en un proyecto grande puede ser realmente difícil.
Esto parece un caso de uso tan común que esperaría una solución más consistente. ¿Hay una mejor manera de hacer esto?
Respuesta #1
Desafortunadamente, no existe una sintaxis incorporada que funcione como una abreviatura para escribir la unión de un tipo con null y undefined. Si deseas tal comportamiento, necesitarás hacerlo manualmente, o definir o importar un tipo de utilidad reutilizable como
type Nullable<T> = T | null | undefined
Para bien o para mal, TypeScript no introducirá un tipo de utilidad así de manera global; esto se solicita ocasionalmente y se rechaza de manera consistente. Vea microsoft/TypeScript#39522 como ejemplo. Su razonamiento es:
Lo que hemos escuchado de los usuarios es que no les gusta cuando añadimos innecesariamente nuevos tipos globales porque a) causa conflictos con los suyos y b) no siempre elegimos la misma definición que ellos estaban usando.
En términos generales, solo introducirán tipos de utilidad si dicho tipo es necesario para producir automáticamente archivos de declaración. Creo que el tipo de utilidad Omit<T, K> se introdujo para representar el comportamiento del operador de propagación en tipos genéricos, pero hubo bastantes desarrolladores de TS del mundo real que estaban usando su propia versión ligeramente diferente de Omit lo cual ahora... Puedes leer más en este hilo de Twitter que explica las trampas con más detalle.
Dado que, al menos hasta ahora, los archivos de declaración no necesitan un tipo utilitario para representar | null | undefined (es difícil imaginar un escenario en el que no se pueda simplemente escribir | null | undefined en el archivo de declaración), no vale la pena para el equipo de TS introducir esto.
Eso deja crearlo tú mismo, o importarlo de alguna biblioteca de tipos TS bien conocida como U.Nullable de ts-toolbelt, o trabajar con otros desarrolladores en un proyecto grande para adherirse a algunos estándares de codificación relacionados con tipos utilitarios. Ninguna de estas opciones es ideal, pero son lo mejor que se puede obtener en ausencia de soporte del lenguaje en sí.
