user1679941
user1679941

Reputation:

How can I define an interface for an array of objects?

I have the following interface and code. I thought I was doing the definitions correctly but I am getting an error:

interface IenumServiceGetOrderBy { id: number; label: string; key: any }[];

and:

getOrderBy = (entity): IenumServiceGetOrderBy => {
        var result: IenumServiceGetOrderBy;
        switch (entity) {
            case "content":
                result =
                [
                    { id: 0, label: 'CId', key: 'contentId' },
                    { id: 1, label: 'Modified By', key: 'modifiedBy' },
                    { id: 2, label: 'Modified Date', key: 'modified' },
                    { id: 3, label: 'Status', key: 'contentStatusId' },
                    { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
                    { id: 5, label: 'Title', key: 'title' },
                    { id: 6, label: 'Type', key: 'contentTypeId' },
                    { id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
                ];
                break;
        }
        return result;
    };

Error:

Error   190 Cannot convert '{}[]' to 'IenumServiceGetOrderBy':
    Type '{}[]' is missing property 'id' from type 'IenumServiceGetOrderBy'

Upvotes: 260

Views: 579447

Answers (17)

JsonKody
JsonKody

Reputation: 717

So I'll add my two cents :)

Let's say you want a Workplace type full of Persons. You need something like this:

Wrong! ... as interface


interface Workplace {
   name: string
   age: number
}[] 
// that [] doesn't work!! ;)

The problem here is that interface is for specifiing Class/Object shape .. not much more. So you may use type instead which is much more flexible

Better -> use type instead of interface


type Workplace = {
   name: string
   age: number
}[] 

// This works :D

But maybe best is ...

define inner object Person with interface and then Workplace as type made by array of persons -> Person[]


interface Person {
   name: string
   age: number
}

type Workplace = Person[]

// nice ;)

Good luck

Upvotes: 26

ExXTreMe315
ExXTreMe315

Reputation: 1

In my case, if I need an Interface for an Array, I use it like this:

interface IBooleanArray {
  0: boolean
  1: boolean
  2: boolean
  3: boolean
}

So if you want an Interface for an Array of Objects, I prefer to do something like:

interface IObjectArray {
  0: { key: number, value: string}
  1: { key: number, value: string}
  2: { key: number, value: string}
  3: { key: number, value: string}
}

Or just create Interfaces for your Objects and use them in your ArrayInterface

Upvotes: 0

Ron B Palmer
Ron B Palmer

Reputation: 39

I ran into this issue passing an array of arrays of on page TOC data from a content page to a Layout page in Astro, basically each array in the array holds three strings. I have a sting for indenting the <ol><li> tags, a string for the id used as the link anchor, and a string for what to display.

While the data for each display page is unique, the display of this data is the same for all content pages, so I put that code in the Layout page. This way I only have to deal with the code once.

The array defined in the content page looks like this:

    const loadOptoc = [
        ['1-0', 'pc-1', 'Troxel v. Granville'],
        ['1-0', 'pc-2', 'Meyer v. Nebraska'],
     ];

the interface in the Layout page looks like this:

    interface Props {
        loadOptoc?: Array<T>;
    }
    interface T {
        U: Array<U>;
    }
    interface U {
        position: string;
        id: string;
        display: string;
    }

Upvotes: 0

Oussama Filani
Oussama Filani

Reputation: 223

You can define a type as an array of objects by simply extending the interface. Here's an example below :

// type of each item in the Service list
interface EnumServiceItem {
    id: string;
    label: string;
}

// type of the Service 
interface ServiceType {
    id: string,
    label: string,
    childList?: Array<EnumServiceItem>
}

// type of the Service list
type ServiceListType = Array<ServiceType>

let draggableList:ServiceListType =  [
        {
            id: "1",
            label: 'Parent Item 1',
            childList: [
                {
                    id: "11",
                    label: 'Child Item 1',
                },
                {
                    id: "12",
                    label: 'Child Item 2',
                }
                ,
                {
                    id: "13",
                    label: 'Child Item 3',
                }
            ]
        },
        {
            id: "2",
            label: 'Parent Item 2',
            childList: [
                {
                    id: "14",
                    label: 'Child Item 4',
                },
                {
                    id: "15",
                    label: 'Child Item 5',
                }
                ,
                {
                    id: "16",
                    label: 'Child Item 6',
                }
            ]
        },
        {
            id: "3",
            label: 'Parent Item 3',
            childList: [
                {
                    id: "17",
                    label: 'Child Item 7',
                },
                {
                    id: "18",
                    label: 'Child Item 8',
                }
                ,
                {
                    id: "19",
                    label: 'Child Item 9',
                }
            ]
        },

    ]

Upvotes: 2

Wilman Sirit
Wilman Sirit

Reputation: 21

I would use the following structure:

interface arrayOfObjects extends Array<{}> {}

And then it's easier to define:

let myArrayOfObjects: arrayOfObjects = [
  { id: 0, label: "CId", key: "contentId" },
  { id: 1, label: "Modified By", key: "modifiedBy" },
  { id: 2, label: "Modified Date", key: "modified" },
  { id: 3, label: "Status", key: "contentStatusId" },
  { id: 4, label: "Status > Type", key: ["contentStatusId", "contentTypeId"] },
  { id: 5, label: "Title", key: "title" },
  { id: 6, label: "Type", key: "contentTypeId" },
  { id: 7, label: "Type > Status", key: ["contentTypeId", "contentStatusId"] },
];

Upvotes: 1

Dane Brouwer
Dane Brouwer

Reputation: 2972

Additional easy option:

    interface simpleInt {
        id: number;
        label: string;
        key: any;
    }

    type simpleType = simpleInt[];

Upvotes: 84

Ericgit
Ericgit

Reputation: 7103

Use like this!

interface Iinput {
  label: string
  placeholder: string
  register: any
  type?: string
  required: boolean
}


// This is how it can be done

const inputs: Array<Iinput> = [
  {
    label: "Title",
    placeholder: "Bought something",
    register: register,
    required: true,
  },
]

Upvotes: 19

Amel
Amel

Reputation: 793

Here is one solution adapted to your example:

interface IenumServiceGetOrderByAttributes { 
  id: number; 
  label: string; 
  key: any 
}

interface IenumServiceGetOrderBy extends Array<IenumServiceGetOrderByAttributes> {

}

let result: IenumServiceGetOrderBy;

With this solution you can use all properties and methods of the Array (like: length, push(), pop(), splice() ...)

Upvotes: 1

Douglas
Douglas

Reputation: 37781

You can define an interface with an indexer:

interface EnumServiceGetOrderBy {
    [index: number]: { id: number; label: string; key: any };
}

Upvotes: 170

Jeremy Levett
Jeremy Levett

Reputation: 947

Do not use

interface EnumServiceGetOrderBy {
    [index: number]: { id: number; label: string; key: any };
}

You will get errors for all the Arrays properties and methods such as splice etc.

The solution is to create an interface that defines an array of another interface (which will define the object)

For example:

interface TopCategoriesProps {
  data: Array<Type>;
}
interface Type {
  category: string;
  percentage: number;
}

Upvotes: 33

Rahmat Ali
Rahmat Ali

Reputation: 1541

Programming is simple. Use simple usecase:

interface IenumServiceGetOrderBy { id: number; label: string; key: any }
 // OR
interface IenumServiceGetOrderBy { id: number; label: string; key: string | string[] }

// use interface like
const result: IenumServiceGetOrderBy[] = 
                [
                    { id: 0, label: 'CId', key: 'contentId' },
                    { id: 1, label: 'Modified By', key: 'modifiedBy' },
                    { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] }
                ];


Upvotes: 1

Graham Mills
Graham Mills

Reputation: 91

In Angular use 'extends' to define the interface for an 'Array' of objects.

Using an indexer will give you an error as its not an Array interface so doesn't contain the properties and methods.

e.g

error TS2339: Property 'find' does not exist on type 'ISelectOptions2'.

// good    
export interface ISelectOptions1 extends Array<ISelectOption> {}

// bad
export interface ISelectOptions2 {
    [index: number]: ISelectOption;
}

interface ISelectOption {
    prop1: string;
    prop2?: boolean;
}

Upvotes: 8

Rolly
Rolly

Reputation: 3385

Also you can do this.

            interface IenumServiceGetOrderBy {
                id: number; 
                label: string; 
                key: any;
            }

            // notice i am not using the []
            var oneResult: IenumServiceGetOrderBy = { id: 0, label: 'CId', key: 'contentId'};

            //notice i am using []
            // it is read like "array of IenumServiceGetOrderBy"
            var ArrayOfResult: IenumServiceGetOrderBy[] = 
            [
                { id: 0, label: 'CId', key: 'contentId' },
                { id: 1, label: 'Modified By', key: 'modifiedBy' },
                { id: 2, label: 'Modified Date', key: 'modified' },
                { id: 3, label: 'Status', key: 'contentStatusId' },
                { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
                { id: 5, label: 'Title', key: 'title' },
                { id: 6, label: 'Type', key: 'contentTypeId' },
                { id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
            ];

Upvotes: 4

CiriousJoker
CiriousJoker

Reputation: 582

Here's an inline version if you don't want to create a whole new type:

export interface ISomeInterface extends Array<{
    [someindex: string]: number;
}> { };

Upvotes: 8

Euan Millar
Euan Millar

Reputation: 466

Easy option with no tslint errors ...

export interface MyItem {
    id: number
    name: string
}

export type MyItemList = [MyItem]

Upvotes: 5

NoNameProvided
NoNameProvided

Reputation: 8997

You can define an interface as array with simply extending the Array interface.

export interface MyInterface extends Array<MyType> { }

With this, any object which implements the MyInterface will need to implement all function calls of arrays and only will be able to store objects with the MyType type.

Upvotes: 147

basarat
basarat

Reputation: 276343

You don't need to use an indexer (since it a bit less typesafe). You have two options :

interface EnumServiceItem {
    id: number; label: string; key: any
}

interface EnumServiceItems extends Array<EnumServiceItem>{}


// Option A 
var result: EnumServiceItem[] = [
    { id: 0, label: 'CId', key: 'contentId' },
    { id: 1, label: 'Modified By', key: 'modifiedBy' },
    { id: 2, label: 'Modified Date', key: 'modified' },
    { id: 3, label: 'Status', key: 'contentStatusId' },
    { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
    { id: 5, label: 'Title', key: 'title' },
    { id: 6, label: 'Type', key: 'contentTypeId' },
    { id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
];

// Option B
var result: EnumServiceItems = [
    { id: 0, label: 'CId', key: 'contentId' },
    { id: 1, label: 'Modified By', key: 'modifiedBy' },
    { id: 2, label: 'Modified Date', key: 'modified' },
    { id: 3, label: 'Status', key: 'contentStatusId' },
    { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
    { id: 5, label: 'Title', key: 'title' },
    { id: 6, label: 'Type', key: 'contentTypeId' },
    { id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
]

Personally I recommend Option A (simpler migration when you are using classes not interfaces).

Upvotes: 392

Related Questions