0

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 <>.

2 Answers 2

1

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']
}

Docs

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
Sign up to request clarification or add additional context in comments.

5 Comments

Would it be far more complex if ImportAccountsState was generic?
Updated. Not complex. You just have to add generic everywhere where you are using ImportAccountsState
Sorry, I wasn't clear enough. I meant if I wasn't using ImportAccountState but an interface with different keys but having StateVariable as values too.
Something like [Prop in keyof T]: T[Prop][...]
I am getting an error when using Result<ImportAccountsState> - Type 'ImportAccountsState' does not satisfy the constraint 'Record<PropertyKey, { value: unknown; }>'. Index signature is missing in type 'ImportAccountsState'.
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.