2

I am new to typescript and learning typescript by writing it.

I am trying below code but it is not letting me access the field of the type passed to function.

Code :


interface Overview1 {
    name: string;
    family: string;
}

interface Overview2 {
    name: string;
    storage: string;
}


type OverView = Overview1 | Overview2;

function LogKeyValuePair(data: OverView) {
    const keys : string[] = Object.keys(data);
    keys.forEach((key) => {
        console.log(data[key])
    })
}

const o2 = {
    name: "john",
    storage: "10 gb"
}

LogKeyValuePair(volume)

Error: error is at this line console.log(data[key])

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'OverView'. No index signature with a parameter of type 'string' was found on type 'OverView'.

1
  • Well it sort of answered it but I has some other related queries..@sergdenisov Commented Feb 29, 2024 at 14:32

3 Answers 3

2

You are trying to use string as a key for the OverView type, which only has 3 keys: name, family, storage. Since string may be any possible string the compiler complains about the index access. Even if you remove the explicit string[] from the type of the keys, the error will remain, since Object.keys is not generic and always returns an array of string.

Possible solutions:

  • Create a typed version of Object.keys
  • Use as assertion to cast the type of the keys to an array of keys of OverView

In this answer I will go with the second one:

function LogKeyValuePair(data: OverView) {
  const keys = Object.keys(data) as (keyof OverView)[];
  keys.forEach((key) => {
    console.log(data[key]); // no error
  });
}

Note that since the OverView is a union the keys will be an array of name because it is the only common key name among the unions.

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

2 Comments

hey thanks, it worked like a charm. Although, I did not get why compiler is complaining about the key (string). Type 'Overview' is a union of types so even if the key is not present it should give some null values, right?
Well, we are speaking about typescript which is strict in this context. Why should it allow passing any string if the only valid ones are name, family, .etc? Check this playground.
0

The problem is that the type of key (=string) is not specific enough to index data (=OverView). You'd need keyof OverView. However, Object.keys() only returns an array of arbitrary strings. I think the best workaround is to use a type assertion here.

interface Overview1 {
  name: string;
  family: string;
}

interface Overview2 {
  name: string;
  storage: string;
}

type OverView = Overview1 | Overview2;

function LogKeyValuePair(data: OverView) {
  const keys = Object.keys(data) as (keyof OverView)[];
  keys.forEach((key) => {
    console.log(data[key]);
  });
}

const o2 = {
  name: "john",
  storage: "10 gb",
};

LogKeyValuePair(o2);

TypeScript Playground

Comments

0

Error: error is at this line console.log(data[key]) Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'OverView'. No index signature with a parameter of type 'string' was found on type 'OverView'.

Since keys are type of string[]. typescript doesn't know the key belongs to Overview type. here are some potential solutions to fix this error.

Infer type using as keyword

by adding this code console.log(data[key as keyof OverView]) typescript will know the key is from the Overview type.

Note! This will work but it can lead to runtime error better solution will be to check the null before accessing properties on the data object.

interface Overview1 {
    name: string;
    family: string;
}

interface Overview2 {
    name: string;
    storage: string;
}


type OverView = Overview1 | Overview2;

function LogKeyValuePair(data: OverView) {
    const keys : string[] = Object.keys(data);
    keys.forEach((key) => {
      console.log(data[key as keyof OverView])
    })
}

const o2 = {
    name: "john",
    storage: "10 gb"
}

LogKeyValuePair(o2)

or infer type while assigning array of keys

function LogKeyValuePair(data: OverView) {
    const keys = Object.keys(data) as (keyof OverView)[];
    keys.forEach((key) => {
      console.log(data[key])
    })
}

Playground link

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.