Suppose I have interface
interface X {
a: string;
b: number;
c: boolean;
}
and a function
function values(x: X) {
return Object.keys(x).map(s => x[s])
}
When I enable typescript's strict
flag I get the error "Element implicitly has an 'any' type because type 'X' has no index signature". So to make it explicit, I can just add an index signature to the definition of X
[key: string]: any;
Easy peasy.
However if I X is now a mapped type instead:
type X<T> = {
[P in keyof T]: string;
}
and I have the function
function values<T>(x: X<T>) {
return Object.keys(x).map(s => x[s])
}
where am I supposed to add the index signature? Is there any way to make this explicit without resorting to doing something gross like Object.keys(x).map(s => (x as any)[s])
You can:
interface X {
a: string;
b: number;
c: boolean;
[key: string]: X[keyof X];
}
The result of X[keyof X]
will now be (string | number | boolean)
, which works even better than any
because the return of your function will be (string | number | boolean)[]
.
Another way that should work with both examples is:
function values(x: X) {
const keys = Object.keys(x) as (keyof X)[];
return keys.map(s => x[s]);
}
Not pretty, but at least more typed than (x as any)
.
Of course it can be made generic too:
function values<T>(x: T) {
const keys = Object.keys(x) as (keyof T)[];
return keys.map(s => x[s]);
}