打字稿错误:类型“字符串”不能用于索引类型 X

Ama*_*rsh 12 typescript

我有一个简单的代码:

const allTypes = { jpg: true, gif: true, png: true, mp4: true };
const mediaType = url.substring(url.lastIndexOf('.') + 1).toLowerCase();
return Boolean(allTypes[mediaType]);
Run Code Online (Sandbox Code Playgroud)

打字稿抱怨:

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
Run Code Online (Sandbox Code Playgroud)

我想我需要将其mediaType视为keyof typeof allTypes,但不知道如何处理。请帮忙

为了完成,完整的代码是:

// 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>
    );
};
Run Code Online (Sandbox Code Playgroud)

Chr*_*ert 29

您只需要定义索引签名

const allTypes: {[key: string]: boolean} = { jpg: true, gif: true, png: true, mp4: true };
Run Code Online (Sandbox Code Playgroud)

可索引类型

类似于我们如何使用接口来描述函数类型,我们也可以描述我们可以“索引到”的类型,如a[10], 或ageMap["daniel"]。可索引类型有一个索引签名,它描述了我们可以用来索引对象的类型,以及索引时相应的返回类型。让我们举个例子:

interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];
Run Code Online (Sandbox Code Playgroud)

上面,我们有一个StringArray带有索引签名的接口。此索引签名指出,当 aStringArray用 a 索引时number,它将返回 a string

  • 我建议看看下面 LCC 的答案。Record&lt;&gt; 和不受约束的索引签名的问题在于您将类型扩展到所有可能的记录。因此,如果我要求“allTypes[“not-a-picture”]”,TSC 会假设结果值为布尔值,即使它是“未定义”的。如果您对“未定义”进行了检查,ESLint 会告诉您这是不必要的检查,即使它是必要的。您正在将键映射到值。为什么不使用 Map&lt;&gt;? (4认同)

LCC*_*LCC 27

allTypes您可以使用可索引类型,但是当您想要支持的键列表有限时,这会扩大 的类型以包含任何(字符串)键。

一个更好的解决方案 - 允许您使用正确的类型allTypes- 是(正如您在问题中已经指出的那样)告诉编译器您的假设是带有类型断言类型mediaType键之一: allTypes

return Boolean(allTypes[mediaType as keyof typeof allTypes]);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,此类型相当于联合类型 "jpg" | "gif" | "png" | "mp4",但它是自动计算的。

(当然,如何确保您的假设在运行时正确是一个单独的问题。)