sobrecarga - Qué hacer con el crecimiento de sobrecargas de funciones en Typescript con variables opcionales
Estoy teniendo dificultades para encontrar una solución para lidiar con el crecimiento exponencial de las sobrecargas de funciones en TypeScript, aquí está el problema:
Supongamos que tengo una función findOne que recibe un id, busca en la base de datos y encuentra a una Persona:
findOne(id):Promise<Person| undefined> {
return query().findById(id);
}
Ahora puedo agregar una variable para lanzar un error si no se encuentra a la persona (el id no existe) y asegurarme de que findOne no esté devolviendo undefined si se pasa la variable;
findOne(id):Promise<Person|undefined>;
findOne(id,orFail:true):Promise<Person>;
findOne(id,orFail?:true):Promise<Person|undefined> {
if (orFail){
return query().findById(id).throwIfNotFound();
}
return query().findById(id);
}
Ahora, ¿qué pasa si tengo otra variable que decide si un campo de persona debería unirse o no? sí, multiplica los tipos de retorno por 2 (añadiendo otra posibilidad para que cada uno de los anteriores tenga un campo unido o no)
De nuevo, si tengo más variables, cada una la multiplicará por 2, así que creo que tendré 2^optionalVarialesCount sobrecargas de la función findOne.
¿Hay una manera mejor de hacer esto? No quiero sobrecargar 16 veces por 4 variables opcionales, realmente hace que el código sea desordenado.
Respuesta #1
Primero, definamos las props opcionales como una tupla:
type Optional = [onFail: true, onPass: false]
Puedes definir cualquier número de props que desees en la tupla Optional.
Ahora podemos sobrecargar nuestra función:
type Person = {
tag: 'Person'
}
type Optional = [onFail: true, onPass: false]
function findOne<
/**
* Infer rest arguments
*/
Rest extends Partial<Optional>,
/**
* 1) if length of Rest arguments extends length of Optional arguments
* it means that all Optional arguments was provided, which in tirn means that
* we should return Promise<Person>
*
* 2) otherwise, if Rest length is less then Optional length, it means
* that no all Optional arguments was passes, which in turn means
* that we should return Promise<Person | undefined>
*/
Return extends {
all_passed: Promise<Person>,
not_all_passed: Promise<Person | undefined>,
}[
Rest['length'] extends Optional['length'] ? 'all_passed' : 'not_all_passed'
]
>(id: string, ...args: Rest): Return
function findOne(id: string, ...args: Partial<Optional>): Promise<Person | undefined> {
return null as any
}
// Promise<Person | undefined> because not optional arguments are passed
const _ = findOne('id', true)
// Promise<Person> because all optional arguments are passed
const __ = findOne('id', true, false)
Parque infantil
