Por favor, eche un vistazo a este código mecanografiado:
type params1 = {p:number} ; type params2 = {p:boolean}; type params3 = {p:string}; type res = {r:string}; const fObject = { a:(a:params1):res=>{return {r:`${ap}`}}, b:(a:params2):res=>{return {r:`${ap?1:0}`}}, c:(a:params3):res=>{return {r:ap}} }
¿Cómo podemos crear un tipo que se vea así:
escriba parámetros = parámetros1 | params2 | params3
Estoy creando un nuevo objeto que tendrá todas las funciones de fObject
pero ejecutará una función de registro en el resultado de cada función.
al igual que:
const loggingObject: typeof fObject = Object.keys(fObject).reduce( (result: any, key: string) => { result[key] = (args: any/*reason for Q*/) => logger.report(fObject [key as loggingObject](args /*If i put something like 2 it says it has no properties in common with params1 & param2 & param3, thats why I know its possible*/)); return result; }, {}, );
No quiero ningún tipo y necesito un tipo dinámico que pueda tomar un objeto con función y dar una unión de todos los tipos de parámetros de todas las funciones en el objeto.
Gran pregunta. Esto es posible, ¡de múltiples maneras! En esta solución utilizaremos las siguientes técnicas:
Los enlaces pueden ser útiles si desea profundizar un poco y si mis explicaciones no son lo suficientemente coherentes. Al final tendremos un tipo que funciona así:
// your code here... type MyParams = ParamForKeys<typeof fObject>; // => `type MyParams = param1 | param2 | param3`
Entonces, lo que vamos a hacer es asignar las claves de fObject
y reemplazar cada clave con el tipo de argumento de su función. La asignación de claves se ve así:
type MyParams<T> = { [key in keyof T]: ... }
Ahora queremos extraer el tipo de argumento. Esto usará tipos condicionales. Los tipos condicionales nos permiten hacer condiciones, así como extraer un argumento mediante inferencia, con la tecla infer
:
type UnwrapPromise<T> = T extends Promise<infer Inner> ? Inner : never; type A = UnwrapPromise<Promise<number>> // => number type B = UnwrapPromise<number> // => never
Y ese es el método exacto que vamos a usar:
type GetFirstParam<T> = T extends ((param: infer Param) => any) ? Param : never
Y ahora si construimos esto juntos obtendremos:
type GetFirstParam<T> = T extends ((param: infer Param) => any) ? Param : never type ParamForKeys<T> = { [key in keyof T]: GetFirstParam<T[key]> }
pero eso nos da el siguiente tipo:
type MyParams = ParamForKeys<typeof fObject>; // { a: param1, b: param2, c: param3 }
Para recuperar los valores en un formato de unión ( param1 | param2 | param3
) podemos acceder a ellos así:
type GetFirstParam<T> = T extends ((param: infer Param) => any) ? Param : never type ParamForKeys<T> = { [key in keyof T]: GetFirstParam<T[key]> }[keyof T]
Y esa es la solución. Tenga en cuenta que no estoy seguro de que esta solución sea lo que está buscando: tener {a: param1, b:param2}
tiene más sentido para mí en términos de su situación de registro, pero esa es la solución para su pregunta !
Espero que haya sido claro. Puedes verlo en vivo en este patio de juegos de TypeScript.