Reputation: 1937
I am trying to create yet another interface from the ImportAccountsState
but this time omitting the StateVariable
interface. I want to do it the TypeScript way without defining it manually again.
interface StateVariable<T> {
value: T;
setValue: (value: T) => void;
}
interface ImportAccountsState {
isDialogOpen: StateVariable<boolean>;
organization: StateVariable<string>;
isOrganizationValid: StateVariable<boolean>;
}
I want my end result to be like so
interface ImportAccountsState {
isDialogOpen: boolean;
organization: string;
isOrganizationValid: boolean;
}
I kind of made a start with keyof ImportAccountsState
but couldn't figure out how to map it to whatever type is inside the angle brackets <>
.
Upvotes: 0
Views: 50
Reputation: 33041
You can use mapped types for this purpose
interface StateVariable<T> {
value: T;
setValue: (value: T) => void;
}
interface ImportAccountsState {
isDialogOpen: StateVariable<boolean>;
organization: StateVariable<string>;
isOrganizationValid: StateVariable<boolean>;
}
type Result = {
[Prop in keyof ImportAccountsState]: ImportAccountsState[Prop]['value']
}
Would it be far more complex if ImportAccountsState was generic?
interface StateVariable<T> {
value: T;
setValue: (value: T) => void;
}
// not sure where you want to use T generic
interface ImportAccountsState {
isDialogOpen: StateVariable<boolean>;
organization: StateVariable<string>;
isOrganizationValid: StateVariable<boolean>;
}
type Result<T extends Record<PropertyKey, { value: unknown }>> = {
[Prop in keyof T]: T[Prop]['value']
}
I am getting an error when using Result Just use
type
instead of interface:
// not sure where you want to use T generic
type ImportAccountsState = {
isDialogOpen: StateVariable<boolean>;
organization: StateVariable<string>;
isOrganizationValid: StateVariable<boolean>;
}
types
have index signature if you want to constraint it
OR move constraint inside the iteration:
interface StateVariable<T> {
value: T;
setValue: (value: T) => void;
}
// not sure where you want to use T generic
interface ImportAccountsState {
isDialogOpen: StateVariable<boolean>;
organization: StateVariable<string>;
isOrganizationValid: StateVariable<boolean>;
}
type Util<T> = {
[Prop in keyof T]: T[Prop] extends { value: unknown } ? T[Prop]['value'] : never
}
type Result = Util<ImportAccountsState> // ok
Upvotes: 1
Reputation: 120380
You can create a type to extract the generic type from StateVariable<T>
:
type ExtractGeneric<T extends StateVariable<any>> =
T extends StateVariable<infer TT> ? TT : never;
Here, we can be sure that because T
is constrained to be of type StateVariable<any>
that the never
branch above will never happen because the type-checker will spew.
Now we can create a mapped type that makes use of the ExtractGeneric
type:
type MappedStateVariableRecord<T extends Record<keyof T, StateVariable<any>>> = {
[P in keyof T]: ExtractGeneric<T[P]>
}
then use this type on your ImportAccountsState
:
type MappedImportAccountsState = MappedStateVariableRecord<ImportAccountsState>
See Playground Link
Upvotes: 1