I want to use a property within a Typescript Interface's instance to compute a second property. I've been looking into Generics but I'm not successfully implementing this yet. :
Here's an example
// Here I define all valid names - works fine!
type ModalNames = 'payment' | 'source'
// This interface implements all expected payloads
// for each name
interface ModalPayloads {
payment: {
plan: string
}
source: {
metadataId: string
}
}
// How do I use the instance name
// to grab the correct payload property?
export interface ShowModalPayload {
name: ModalNames
modalProps?: ModalPayloads[instance.name]
}
In other words, for a given instance
of ShowModalPayload
, I want to assign modalProps
to a type derived from instance.name
.
Hopefully this makes sense!
I'd use generics for this:
export interface ShowModalPayload<K extends ModalNames> {
name: K
modalProps?: ModalPayloads[K]
}
Note the use of ModalPayloads[K]
in place of ModalPayloads[instance.name]
. That's called a lookup type and it allows you to describe the type of m[k]
where m
has type ModalPayloads
and k
has type K
.
Anyway the ShowModalPayload
interface is now generic in K
, which should be one of the ModalNames
literals:
declare const smpPayment: ShowModalPayload<'payment'>;
smpPayment.name // "payment"
smpPayment.modalProps // {plan: string} | undefined
declare const smpSource: ShowModalPayload<'source'>;
smpSource.name // "source"
smpSource.modalProps // {metadataId: string} | undefined
Those correspond to what you're looking for, I think. Note that the following is still possible:
declare const smpWhoKnows: ShowModalPayload<ModalNames>
smpWhoKnows.name // ModalNames
smpWhoKnows.modalProps // {plan: string} | {metadataId: string} | undefined
which is possibly not what you want, but is not prohibited. The above definition is probably sufficient for most use cases, though.
Hope that helps. Good luck!