When typing functions what I care about the most is argument and return types.
You could type the arguments like this:
<InputProps, TargetProps extends Record<keyof TargetProps, keyof InputProps>>(
source: InputProps,
params: TargetProps
) => ...
Typescript will complain if the second object doesn't match the first one.
For the return value you can define a utility type as follows:
type MapFrom<A, B> = Record<keyof A, B[keyof B]>;
By using the Object.proptotype.entries type argument we avoid having to cast sourceProp.
To keep the function signature we need to assert the type of initialValue in the reduce.
I also use const assertions to give object literals readonly properties
This is the complete result:
type MapFrom<A, B> = Record<keyof A, B[keyof B]>;
const obj1 = {
host: "clientNameHost",
pass: "clientNamePass"
} as const;
const obj2 = {
clientNamePass: "12345",
clientNameHost: "http://localhost:3000"
} as const;
const mapParams = <InputProps, TargetProps extends Record<keyof TargetProps, keyof InputProps>>(
source: InputProps,
params: TargetProps
) =>
Object.entries<keyof InputProps>(params).reduce(
(acc, [param, sourceProp]) => ({
...acc,
[param]: source[sourceProp]
}),
{} as MapFrom<TargetProps, InputProps>
);
const obj3 = mapParams(obj2, obj1);
Here you can try it out.
sourceProp as keyof Tlike so:const mapParams = <T, K>(source: T, params: K) => Object.entries(params).reduce((acc, [param, sourceProp]) => ({ ...acc, [param]: source[sourceProp as keyof T] }), {});