I'm trying to make type-safe handlers for redux actions relying on action type. For example, any action could be described as:
type ActionType<T extends string> = {
type: T
};
For a specific action one can have:
type MyAction = ActionType<'hey' | 'there'>;
Now, I'd like to restrict a handler function to allow only 'hey' or 'there' as a type. Finally I expect something like this:
handleAction<MyAction>('hey');
where the definition of the handler function could be:
function handleAction<A extends ActionType<T>>(type: T){
...
}
But I have a typescript compiler error:
TS2304: Cannot find name 'T'.
So, I have to modify this handler function definition in this way:
function handleAction<A extends ActionType<T>, T extends string>(type: T){
...
}
It works, but looks really ugly:
handleAction<MyAction, 'hey' | 'there'>('hey');
TS Playground
What's a better way to handle this?
Generics allow creating 'type variables' which can be used to create classes, functions & type aliases that don't need to explicitly define the types that they use. Generics makes it easier to write reusable code.
TypeScript - Generic Interface The above IProcessor is a generic interface because we used type variable <T> . The IProcessor interface includes the generic field result and the generic method process() that accepts two generic type parameters and returns a generic type. As you learned, you can use interface as type.
This article opts to use the term type variables, coinciding with the official Typescript documentation. T stands for Type, and is commonly used as the first type variable name when defining generics. But in reality T can be replaced with any valid name.
This is not possible.
Using Class Types in Generics. When creating factories in TypeScript using generics, it is necessary to refer to class types by their constructor functions. For example, function create < Type > ( c: { new (): Type }): Type {. return new c ();
This Generic functions it is really useful if you want to clear your code or receive specific types on your parameters, it helps us when we specified types with interfaces either it looks clean, and it helps a lot to the IDE to kow what r you trying to do with your code. JavaScript With Syntax For Types.
In languages like C# and Java, one of the main tools in the toolbox for creating reusable components is generics, that is, being able to create a component that can work over a variety of types rather than a single one. This allows users to consume these components and use their own types.
Generic classes are only generic over their instance side rather than their static side, so when working with classes, static members can not use the class’s type parameter.
Edit
You can use a type query to get the type of type
:
function handleAction<A extends ActionType<string>>(type: A ['type']) {
}
handleAction<MyAction>('hey');
Or you can use conditional types in 2.8 to extract the generic parameter from ActionType
(2.8 is unreleased at the time of writing, but will be released in March 2018, you can get it via npm install -g typescript@next
)
type ActionType<T extends string> = {
type: T
};
type MyAction = ActionType<'hey' | 'there'>;
function handleAction<A extends ActionType<string>>(type: A extends ActionType<infer U> ? U : never) {
}
handleAction<MyAction>('hey');
This solution is based on the inference behavior of conditional type. ActionType<infer U>
basically says: If a extends ActionType
of some other type U
give me the type U
. So U
will be whatever string literal type was passed to ActionType
in our case. Then we use U
on the true branch of the conditional type and this becomes the final type of out conditional type. In this case we don't care about the false branch so we use never.
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