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>(...);
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> .
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.
The actual type arguments of a generic type are. reference types, wildcards, or. parameterized types (i.e. instantiations of other generic types).
type GetInnerType<S> = S extends SomeInterface<infer T> ? T : never
usage:
type InnerType = GetInnerType<typeof someInstance>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With