dwjohnston
dwjohnston

Reputation: 11791

Get corresponding type when using Typescript's keyof?

I want to do something like this:

interface StateItem<T extends StateItemType>{
    id: string;
    values: {
        [key in keyof T]: Provider<corresponding typeof T>
    }
}

type Primitive = number | string | Position; 

interface StateItemType {
    [key: string] : Primitive; 
}

interface Mover extends StateItemType  {
    center: Position; 
    speed: number; 
    vector: Position; 
    accruedVector: Position;
}

const mover : StateItem<Mover> = {
    id: "123", 
    values: {
         center: createRandomPosition(), 
         speed: createRandomNumber(), 
         vector: createRandomPosition(), 
         accruedVector: createRandomPosition(), 
    }
}


That is, given an interface T which is a straightforward key:type map, when I create a StateItem<T> an instances of that must have a values object that contains all of those keys, and Provider<type> instances.

How would I do this?

Upvotes: 0

Views: 764

Answers (1)

ford04
ford04

Reputation: 74500

You can use the following type to access the property value type for each key in T:

interface StateItem<T extends StateItemType>{
    id: string;
    values: {
        [key in keyof T]: Provider<T[key]>>
    }
}

The construct {[key in keyof T]: Provider<T[key]>} is called a mapped type. It creates a new type, where each key in T is mapped to a new property value type.

key is a type variable and points to the currently used key, similar to a for...in loop, where you can access each property successively with an index variable. key can also be used in the property value type declaration part of the mapped type. By the way: you can rename key as you like, often short names like P or K are used to distinguish those index type variables from real types.

Inside the mapped type, T[key] would lookup the property value type for the currently accessed property key hold by key variable inside T (the typed to be mapped). So, something like this effectively is a NOOP:

type T1 = { foo: string; bar: number }
type T2 = {[K in keyof T1]: T1[K]} // not very interesting type...

Hope, it makes things a bit more clear!

Upvotes: 2

Related Questions