ragelo
ragelo

Reputation: 53

TypeScript advanced type checks

Check please the comments in the code. Is it possible to get what I want or TS has no such functionality?

I need type checks for my addToRegistry function.

TypeScript playground with code

type MessageHandler<T> = ((data: T) => void) | ((data: T) => Promise<void>);

interface AuthPayload {
    id: string;
}

class HandlersRegistry {
    auth?: MessageHandler<AuthPayload>;
    test?: MessageHandler<number>;
}

const registry = new HandlersRegistry();

// handler type should ref on HandlersRegistry[key] by eventType
// function addToRegistry<T>(eventType: keyof HandlersRegistry, handler: ???) {
function addToRegistry<T>(eventType: keyof HandlersRegistry, handler: MessageHandler<T>) {
    registry[eventType] = handler; // should not be an error
}

const authHandler: MessageHandler<AuthPayload> = (data: AuthPayload) => null;

// correct
addToRegistry('auth', authHandler);
// correct, shows error, but I don't want to provide type of payload every time
addToRegistry<number>('test', authHandler);
// should show error, but doesn't
addToRegistry('test', authHandler);

Thanks for the answers!

Upvotes: 2

Views: 119

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249616

You can use a generic type to hold the type of the key and a type query to specify the parameter must be the same type as the field type:

type MessageHandler<T> = ((data: T) => void) | ((data: T) => Promise<void>);

interface AuthPayload {
    id: string;
}

class HandlersRegistry {
    auth?: MessageHandler<AuthPayload>;
    test?: MessageHandler<number>;
}

const registry = new HandlersRegistry();

// handler type should ref on HandlersRegistry[key] by eventType
// function addToRegistry<T>(eventType: keyof HandlersRegistry, handler: ???) {
function addToRegistry<K extends keyof HandlersRegistry>(eventType: K, handler: HandlersRegistry[K]) {
    registry[eventType] = handler; // should not be an error
}

const authHandler: MessageHandler<AuthPayload> = (data: AuthPayload) => null;

// correct
addToRegistry('auth', authHandler);
// correct, shows error, but I don't want to provide type of payload every time
addToRegistry<number>('test', authHandler);
// show error as expected
addToRegistry('test', authHandler); 

Upvotes: 1

Related Questions