Typescript: Type annotation for object with unknown properties but known property types?

Created on 4 Apr 2016  路  6Comments  路  Source: microsoft/TypeScript

I have encounter a few times in multiple applications an scenario in which I don't know the properties of an object but I do know that all its properties are of a certain type.

For example:

interface Metadata {
  key: string,
  value: any
}

var metadata = {
  someReducer: Metadata ,
  anotherReducer: Metadata , 
  // ...
}

In this scenario:

  • I don't know the property names or number of properties of metadata
  • I do know that Metadata is the type of all the properties of metadata

Now let's imagine that a function take the metadata object as argument:

function doSomething(metadata: any) {
  // ...
}

I used any as the type of the argument metadata but It would be great if I could let developers know that all the properties of this object must be of type Metadata.

is there any way to create such type annotation?

Most helpful comment

interface MetadataObj {
    [key: string]: Metadata
}
function doSomething(metadata: MetadataObj) {

or

type MetadataObj = {[key: string]: Metadata}
function doSomething(metadata: MetadataObj) {

or

function doSomething(metadata: {[key: string]: Metadata}) {

It is called index signature.

All 6 comments

interface MetadataObj {
    [key: string]: Metadata
}
function doSomething(metadata: MetadataObj) {

or

type MetadataObj = {[key: string]: Metadata}
function doSomething(metadata: MetadataObj) {

or

function doSomething(metadata: {[key: string]: Metadata}) {

It is called index signature.

I'm just sharing in case it is useful for others...

The following doesn't work:

interface Metadata {
  key: string,
  value: any
}

interface MetadataObj {
    [key: string]: Metadata
}

// no explicitly typed!
var metadata = {
  someReducer: { key: "test", value: 1 } ,
  anotherReducer: { key: "test", value: 2 }
  // ...
};

function doSomething(metadata: MetadataObj) {
  // ...
}

doSomething(metadata);

The following works:

interface Metadata {
  key: string,
  value: any
}

interface MetadataObj {
    [key: string]: Metadata
}

var metadata : MetadataObj = { // type annotation here is needed
  someReducer: { key: "test", value: 1 } ,
  anotherReducer: { key: "test", value: 2 }
  // ...
};

function doSomething(metadata: MetadataObj) {
  // ...
}

doSomething(metadata);

Here's a simpler test case:

type Test = { [key: string]: { prop: number } };

let a: Test = { a: { prop: 1 } };  // <-- No error

let b = { a: { prop: 1 } };
let c: Test = b;                   // <-- Error in 1.8.9

This seems to be a bug that may have already been fixed. It errors in 1.8.9 but not on the nightly build.

I believe it was fixed by #7029 (Implicit index signatures). It should probably be included on the next release.

@malibuzios thanks for he details :smile:

Just one question:
In this case: type Test = { [key: string]: { prop: number } };

Why do we have to name those variables? It is totally useless (if I'm wrong please enlighten me)
Wouldn't it be much better with only: type Test = { [string]: {number} };
This is pretty ok, but still few unnecessary characters: type Test = { [_: string]: { _: number } };

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CyrusNajmabadi picture CyrusNajmabadi  路  3Comments

blendsdk picture blendsdk  路  3Comments

wmaurer picture wmaurer  路  3Comments

MartynasZilinskas picture MartynasZilinskas  路  3Comments

kyasbal-1994 picture kyasbal-1994  路  3Comments