简体   繁体   中英

Typescript Error: type 'string' can't be used to index type X

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>
    );
};

All you need is to define the index signature :

const allTypes: {[key: string]: boolean} = { jpg: true, gif: true, png: true, mp4: true };

Indexable Types

Similarly to how we can use interfaces to describe function types, we can also describe types that we can “index into” like a[10] , or ageMap["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 a StringArray is indexed with a number , it will return a string .

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" "jpg" | "gif" | "png" | "mp4" "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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM