One scenario in my application requires me to define message structures using a simple TypeScript generic along with a basic message factory. Here is the solution I devised:
export type Message<
T extends string,
P extends Record<string, any> = Record<string, never>
> = {
type: T;
payload: P;
};
export const msg = <M extends Message<string, Record<string, any>>>(
type: M['type'],
payload: M['payload']
): M => ({ type, payload });
type UserRegistered = Message<'UserRegistered', { name: string }>;
const message = <UserRegistered>msg('UserRegistered', { name: 'Test' });
However, I encounter a TS2322 error on the ): M => ({ type, payload });
line:
error TS2322: Type '{ type: M["type"]; payload: M["payload"]; }' is not assignable to type 'M'. '{ type: M["type"]; payload: M["payload"]; }' can be assigned to the 'M' constraint, but 'M' could potentially be instantiated with a different subtype of constraint 'Message<string, Record<string, any>>'.
I am grappling with understanding why this poses a risk to type safety and why it fails to transpile, given that it essentially involves destructuring and reconstructing the same type.
(In case you are questioning the necessity of this thin factory layer, I believe it will enhance maintainability by providing a large set of predefined named factory functions)