1

The question is a bit hard to explain without showing an example, so let's look at this Message type that will be extended and used as base type for other types.

interface Message<E extends string = string, P = any> {
  topic: E;
  params: P;
}

I have this interface for indicading message type. The topic and parameters are generic to make sure the interface could be extend for different cases like:

interface OrderParams {
  userId: string;
  orderId: string;
}

interface CreateOrderMessage extends Message<'orders.create', OrderParams> {}
interface UpdateOrderMessage extends Message<'orders.update', OrderParams> {}
...

type CustomMessage = CreateOrderMessage | UpdateOrderMessage | ...;

This allows me to add strict typing for topic and params for different topic types which I could use with a class:

class PubSub<T extends Message = Message> {
  publish(message: T): void;
  subscribe(topic: string): void;
}

If we pass CustomMessage as a generic type to PubSub<> it will check typings for publish method, but I also want to make sure topic parameter of subscribe method is also type checked using E generic type of T extends Message generic type.

So, is there a way to somehow extract generic type of another generic type so I could write something like below?

subscribe(topic: GenericOf<T, 0>);             // 1st generic of T type
subscribe(topic: TypeOfObjectKey<T, 'topic'>); // Type of 'topic' property of T type
4
  • Does subscribe(topic: T['topic']) do what you want? I think that covers at least your second example (TypeOfObjectKey<T, 'topic'>). Not sure what you're trying to do with the first (GenericOf<T, 0>). Commented Oct 19, 2021 at 14:20
  • @Wing haven't tried or aware of that, thank you! You can publish it as an answer Commented Oct 19, 2021 at 14:22
  • "Not sure what you're trying to do with the first (GenericOf<T, 0>)" - as I've said I wasn't aware of T[key] so I posted 2 examples whether it's possible to get generic of type or type of property. Commented Oct 19, 2021 at 14:24
  • Ahh ok, I didn't fully understand your question and thought you might be trying something like getting the first type in the union or something like that. Thanks for confirming :) Commented Oct 19, 2021 at 14:32

1 Answer 1

2

subscribe(topic: T['topic']) will ensure the topic parameter of subscribe is the same type as the topic property of the interface passed into the generic. Here's an example derived from the code you've provided in your question (I've made it error so that the underlying type is easily visible):

interface Message<E extends string = string, P = any> {
  topic: E;
  params: P;
}

interface OrderParams {
  userId: string;
  orderId: string;
}

interface CreateOrderMessage extends Message<'orders.create', OrderParams> {}
interface UpdateOrderMessage extends Message<'orders.update', OrderParams> {}

type CustomMessage = CreateOrderMessage | UpdateOrderMessage;

class PubSub<T extends Message = Message> {
  publish(message: T): void {};
  subscribe(topic: T['topic']): void {};
}

new PubSub<CustomMessage>().subscribe('')
                                      ^^
Argument of type '""' is not assignable to parameter of type '"orders.create" | "orders.update"'.

TypeScript Playground

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.