I have a type Command
export type Command<
Type extends string = string,
> = {
type: Type
}
I'm creating a type Handler
like this:
export type Handler<T extends Command> = {
type: Pick<T, 'type'>
}
The goal is to make sure that the type of the returned Handler
here is the same as for the command:
export type MyCommand = Command<'MyCommand'>
const MyHandler = (): Handler<MyCommand> => {
return {
type: 'MyCommand'
}
}
But I'm getting this error:
Type 'string' is not assignable to type 'Pick<MyCommand, "type">'.(2322)
I've created TS playground here.
CodePudding user response:
Pick<T, K>
creates an object type that contains the properties specified in K
. So Pick<MyCommand, 'type'>
is actually { type: 'MyCommand' }
If you just want the type of a property in another type use an index accessed type T[K]
export type Command<
Type extends string = string,
> = {
type: Type
}
export type Handler<T extends Command> = {
type: T['type']
}
export type MyCommand = Command<'MyCommand'>
const MyHandler = (): Handler<MyCommand> => {
return {
type: 'MyCommand'
}
}
CodePudding user response:
You can infer Type
generic type from Command inside Handler like this:
export type Handler<T> = T extends Command<infer Type>
? {type: Type}
: never;
Following description is how I understand inference in this case.
Here we have ternary type where we check that T
in fact extends Command
. If it doesn't extends Command
, we return never
, as it should never happen. But if it does, we infer (get type) value of Command
generic and put it into some kind of type variable Type
. Then we return {type: Type}
as a value of our Handler.