Reputation: 6873
Here is a class:
export class Survey {
isCompleted: boolean;
response: {
'devices': string[];
'languages': string[];
'frameworks': string[];
'backend': string[];
};
}
I'm getting the "Element implicitly has an 'any' type because type '...' has no index signature" error when trying the following:
return Object.keys(user1.response).map(key => {
return percentageMatch(user1.response[key], user2.response[key]) * categoryScores[key];
})
user1
and user2
are instances of the Survey
class.
I know how to set an index signature with simple object literals but how do I do it with the properties of the response
object, which is itself a property of the Survey
class.
Upvotes: 4
Views: 5995
Reputation: 12701
That required adding an index type [key: string]: string[]
to the response
type:
export class Survey {
isCompleted: boolean;
response: {
[key: string]: string[],
devices: string[],
languages: string[],
frameworks: string[],
backend: string[],
};
}
You can check it out in the TypeScript Playground demo that I created.
You could also consider reducing repetition here and extract known keys to a string literal type:
type ResponseKeys = 'devices' | 'languages' | 'frameworks' | 'backend';
export class Survey {
isCompleted: boolean;
response: {
[key in ResponseKeys]: string[]
};
}
Upvotes: 8
Reputation: 51609
Index signature is required because Object.keys()
loses type information and returns string arrays.
You can introduce your own function which is similar to Object.keys()
but is declared to return an array of actual object keys:
function typedKeys<T>(o: T): (keyof T)[] {
// type cast should be safe because that's what really Object.keys() does
return Object.keys(o) as (keyof T)[];
}
Then, there will be no error in a function that iterates keys of one object and accesses another object, if the objects are of the same type:
export class Survey {
isCompleted: boolean;
response: {
'devices': string[];
'languages': string[];
'frameworks': string[];
'backend': string[];
};
}
function f(user1: Survey, user2: Survey) {
return typedKeys(user1.response).map(key => {
return user1.response[key] == user2.response[key];
})
}
Upvotes: 1