186

Assume I have a JSON payload that parses into something like this:

{
    name: "test",
    items: {
        "a": {
            id: 1,
            size: 10
        },
        "b": {
            id: 2,
            size: 34
        }
    }
}

How would I set up the definition of the Example interface to model that the value of the items property is an object whose keys are strings and whose values are defined by the Item interface:

export interface Example {
    name: string;
    items: ???;

}

export interface Item {
    id: number;
    size: number;
}
0

3 Answers 3

294

Typescript allows you to add a type for the object keys using the syntax [key: string].

As stated in the documentation, these are called indexable types:

Indexable types have an index signature that describes the types we can use to index into the object, along with the corresponding return types when indexing.

In your case, you would use the following:

export interface Item {
    id: number;
    size: number;
}

export interface Example {
    name: string;
    items: {
        [key: string]: Item
    };
}

For reference, here is a link to a live example.

Sign up to request clarification or add additional context in comments.

9 Comments

Why do you export Item interface? Isn't exporting just Example interface enough?
@AlexanderKim yes, unless Item is useful to other code using these types as well.
does anyone know how to set the items keys with state and access them?
Thanks for this I had an issue accessing an interface defined in one class file in another class. I had not defined the interface with export. After adding the export the import at the to of the page allowed me to then import the class and the interface thanks.
You're more than welcome and your answer was very useful to me. Thank you!
|
11

You can want can be achieved using Record type

interface Item {
    id: number;
    size: number;
}


interface Example2 {
   name: string;
   items : Record<string, Item>; 

}

var obj2: Example2 = {
    name: "test",
    items: {
        "a": {
            id: 1,
            size: 10
        },
        "b": {
            id: 2,
            size: 34
        },
        "c": {
            id: 3,
            size: 34
        }
    }
}

You will also get compile time check:

enter image description here

Comments

0

The second parameter of Record can also be a Record.

type Weekday = 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday'
type Animal = 'duck' | 'goose' | 'chicken'

type FarmReport = {
    name: string
    items: Record<Weekday, Record<Animal, number>>
    reporter: string
} 

const report: FarmReport = {
    name: 'report 20231101',
    reporter: 'Tom',
    items: {
        'Monday' : {
            duck: 1,
            goose: 2,
            chicken: 3,
        },
        'Tuesday' : {
            duck: 1,
            goose: 2,
            chicken: 3,
        },
        'Wednesday' : {
            duck: 1,
            goose: 2,
            chicken: 3,
        },
        'Thursday' : {
            duck: 1,
            goose: 2,
            chicken: 3,
        },
        'Friday' : {
            duck: 1,
            goose: 2,
            chicken: 3,
        },
    }
}

This is a straightforward way (firstly define Weekday and Animal, then define FarmReport) to have a nested Record. doc

Another way is to use keyof to do it reversely (firstly define FarmReport, then define Weekday and Animal as being extracted from FarmReport). doc

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.