I have a simple code:
const allTypes = { jpg: true, gif: true, png: true, mp4: true };
const mediaType = url.substring(url.lastIndexOf('.') + 1).toLowerCase();
return Boolean(allTypes[mediaType]);
TypeScript is complaining:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ jpg: boolean; gif: boolean; png: boolean; mp4: boolean; }'.
No index signature with a parameter of type 'string' was found on type '{ jpg: boolean; gif: boolean; png: boolean; mp4: boolean; }'. TS7
I think I need to treat mediaType
as keyof typeof allTypes
, but don know how. Please help
For sake of completion, the complete code is:
// these are all the types of media we support
const allTypes = { jpg: true, gif: true, png: true, mp4: true };
const MediaGallery = () => {
const classes = useStyles();
const [ filters, setFilters ] = useState(allTypes);
return (
<div className={classes.root}>
{mediaList
.filter(({ url }) => {
const type = url.substring(url.lastIndexOf('.') + 1).toLowerCase();
return Boolean(filters[type]);
})
.map(({ url, caption, hash }) => <Media url={url} caption={caption} key={hash} />)}
<FiltersPanel onFiltersChanged={(newFilters: any) => setFilters(newFilters)} />
</div>
);
};
TypeScript - String indexOf() This method returns the index within the calling String object of the first occurrence of the specified value, starting the search at fromIndex or -1 if the value is not found.
The error "Element implicitly has an 'any' type because expression of type 'string' can't be used to index type" occurs when we use a string to index an object with specific keys. To solve the error, type the string as one of the object's keys.
The error "Type cannot be used as an index type" occurs when we try to use a type that cannot be used to index an array or object, e.g. one of the non-primitive types like String . To solve the error, use primitive (lowercase) types, e.g. number or string when typing values.
The "Type 'string' is not assignable to type" TypeScript error occurs when we try to assign a value of type string to something that expects a different type, e.g. a more specific string literal type or an enum. To solve the error use a const or a type assertion.
All you need is to define the index signature:
const allTypes: {[key: string]: boolean} = { jpg: true, gif: true, png: true, mp4: true };
Similarly to how we can use interfaces to describe function types, we can also describe types that we can “index into” like
a[10]
, orageMap["daniel"]
. Indexable types have an index signature that describes the types we can use to index into the object, along with the corresponding return types when indexing. Let’s take an example:interface StringArray { [index: number]: string; } let myArray: StringArray; myArray = ["Bob", "Fred"]; let myStr: string = myArray[0];
Above, we have a
StringArray
interface that has an index signature. This index signature states that when aStringArray
is indexed with anumber
, it will return astring
.
Record<Keys, Type>
Another solution is to use the TypeScript utility type Record<Keys, Type>
:
Constructs an object type whose property keys are
Keys
and whose property values areType
. This utility can be used to map the properties of a type to another type.
const allTypes: Record<string, boolean> = { jpg: true, gif: true, png: true, mp4: true };
for (const key of Object.keys(allTypes)) {
console.log(`${key}: ${allTypes[key]}`);
}
You can use indexable types, but this widens the type of allTypes
to contain any (string) key, when it looks like you have a limited list of keys that you want to support.
A better solution - allowing you to use the proper type of allTypes
- is (as you already indicated in your question) to tell the compiler your assumption that mediaType
is one of the keys of the type of allTypes
with a type assertion:
return Boolean(allTypes[mediaType as keyof typeof allTypes]);
This type is in this case equivalent to the union type
"jpg" | "gif" | "png" | "mp4"
, but it is computed automatically.
(How you ensure that your assumption is correct at runtime is a separate concern, of course.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With