If you're searching for TypeScript generics, they allow us to deduce a type from the parameter or argument.
Here's an example to illustrate this concept:
function retrieveType<T>(param: T) {
return param;
}
const returnedValue = retrieveType({ foo:1337 });
// { foo: 1337 }
In this case, the return type of retrieveType
is the same as the parameter type itself. This approach can be extended for more intricate types, such as selecting a single field only.
function extractFooOnly<T>(param: {foo: T}) {
return param.foo;
}
const someFoo = extractFooOnly({foo: 1337});
// will be number
const someFoo2 = extractFooOnly({foo: 'bar'});
// will be string
Alternatively, we can create a function that returns an object with the value obtained from the parameter.
function obtainParamValue<T>(cb: () => T) {
return {
result: cb(),
};
}
const returnValue = obtainParamValue(() => 'foo');
returnValue.result; // will be string
const returnValue2 = obtainParamValue(() => 1337);
returnValue2.result; // will be number
Moreover, we can preprocess the argument and define its return type based on processing using generics.
type ParamDataType<Key extends string, Value extends string> = {
key: Key;
value: Value;
} & Record<Value, true>;
function redefineType<Key extends string, Value extends string>(
param: Record<Key, Value>
): ParamDataType<Key, Value> {
const key = Object.keys(param)[0] as Key;
const value = Object.values(param)[0] as Value;
return Object.assign({}, {
key: key,
value: value,
}, {
[value]: true,
} as Record<Value, true>);
}
const newData = redefineType({hello: 'world'});
newData.key; // string with value 'hello'
newData.value; // string with value 'world'
newData.world; // true without TypeScript error