Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: Get type of an instance's generic

The problem:

Say I have a interface from a third party library that uses generics

interface SomeInterface<T> {
    ...
}

And in my code I have an instance that implements that interface

const someInstance; // type signature: SomeInterface<string>

Given this instance, how would I access the type of the generic type parameter T for that instance (in this example, how would I be able to extract the string type from someInstance)? I don't need it for runtime, I just need it so that I can define what type to expect as an argument in a function:

function someFunction(someArg: ???) {...}

Basically I want to be able to do this, which doesn't work:

function someFunction(someArg: typeof T in someInstance) {...}

Specific use case:

My specific use case here is that I'm using the redux-act and redux-sagas packages. Redux-act provides an action creator factory which produces an action creator with a type signature of ActionCreator<P, M>

// someActionCreator has type signature of ActionCreator<string, void>
const someActionCreator = createAction<string, number>(...); 

When this action creator is called via someActionCreator(payload: P, metadata: M), it produces an Action<P, M>.

// someAction has a type signature of Action<string, number>
const someAction = someActionCreator("foo", 1);

In redux sagas, I have access to the action creator instances (ie someActionCreator), where P and M have defined types, but I don't have access to the actions themselves. However, the handler functions expect the action as the argument, such as

function* someEffectHandler(action: Action<string, void>) {...}

Since Typescript knows what the types of P and M are on someActionCreator, I want to be able to access them inside the type declaration of someEffectHandler. What I'm trying to avoid is having to write tons of boilerplate for every single action, when the action creator should be able to give me the typed parameters.

//Trying to avoid this
type SomeActionPayload = string;
type SomeActionMetadata = number;
export type SomeAction = Action<SomeActionPayload, SomeActionMetadata>;
export const someActionCreator = createAction<SomeActionPayload, SomeActionMetadata>(...);
like image 502
scapper Avatar asked Jan 10 '18 05:01

scapper


People also ask

How do you define a generic type in TypeScript?

TypeScript supports generic classes. The generic type parameter is specified in angle brackets after the name of the class. A generic class can have generic fields (member variables) or methods. In the above example, we created a generic class named KeyValuePair with a type variable in the angle brackets <T, U> .

How do you pass a generic class as parameter in TypeScript?

Assigning Generic ParametersBy passing in the type with the <number> code, you are explicitly letting TypeScript know that you want the generic type parameter T of the identity function to be of type number . This will enforce the number type as the argument and the return value.

Which types can be used as arguments of a generic type?

The actual type arguments of a generic type are. reference types, wildcards, or. parameterized types (i.e. instantiations of other generic types).


1 Answers

type GetInnerType<S> = S extends SomeInterface<infer T> ? T : never

usage:

type InnerType = GetInnerType<typeof someInstance>
like image 56
Erik van Velzen Avatar answered Oct 11 '22 15:10

Erik van Velzen