When it comes to unit tests, I prefer a more flexible approach with dynamic generic types that eliminate the need for type casting.
I want T
to be open-ended, but if I specify a type, I expect to receive an exact match.
For R
, I need it to precisely match the type of params
, regardless of whether T is specified or not.
The issue arises when specifying T
and being required to also define R
. I have attempted setting its default value to { [key: string]: any }
, however, this disrupts the types and fails to accurately reflect the params
type.
declare function test<T, R extends { [key: string]: any } = { [key: string]: any }>(
template: string,
params: R,
): {t: T, r: R};
// testing without specific generics
const test1 = test('f', {
a: 'a',
});
test1.t; // expectedly unknown as no specific type was provided
test1.r.a; // expected behavior - recognized as a string
test1.r.b; // expected failure since property does not exist
// testing with a specified generic
const test2 = test<string>('f', {
a: 'a',
});
test2.t; // expectedly a string
test2.r.a; // failed - treats it as any instead of a string
test2.r.b; // failed - treats it as any instead of forbidding it
// Attempting another solution
declare function anotherTest<T>(
template: string,
params: { [key: string]: any },
): {t: T, r: typeof params}; // aiming for the passed type, not default { [key: string]: any }
It seems challenging to achieve this without separating params into an independent variable and defining its type explicitly. If you have a solution, please share. Thank you in advance!