I have a hard time trying to wrap my head around typescript dynamic (and generic) types.
What I'm trying to accomplish is create a function that returns an object with a specific type where some properties of that object must match whatever parameters are given to that function.
So, basically what I want to happen (pseudo):
const listRequest = createRequest('list', {ids: [1, 2]});
this function should create me an object as follows:
{
operationVersion: 1,
protocolVersion: 2,
operation: 'list', // first param
list: { // prop name must match with first param
ids: [1, 2], // second param
}
}
For now, my code looks like:
interface IBaseRequest {
operationId: number;
protocolVersion: number;
operation: string;
authenticationToken?: string;
}
export type BaseRequest<Operation extends string> = {
[Prop in keyof IBaseRequest]: IBaseRequest[Prop];
} & Record<Operation, any>;
type CreateRequestType = <T extends string>(operation: string, params: any) => BaseRequest<T>;
export const createRequest: CreateRequestType = <T extends string>(operation: string, params: any) => {
const req = {
operation: operation,
operationId: 1,
protocolVersion: 2,
};
req[operation] = params;
return req as BaseRequest<T>;
};
Now, when create my request object with:
const listRequest = createRequest('list', {a: 'aa'});
I don't get the intellisense for listRequest.list nor that the type of listRequest being type of BaseRequest<'list'>
And if try to create the request with:
type ListRequest = 'list';
const test = <ListRequest>createRequest('list', {a: 'aa'});
I get an error:
Conversion of type 'BaseRequest<string>' to type '"list"' may be a mistake
because neither type sufficiently overlaps with the other. If this was
intentional, convert the expression to 'unknown' first.ts(2352)
Is there a way to accomplish this with types and generics?
IBaseRequestas class and not interface?