TypeScript解构时指定特定类型遇问题:类型不匹配报错求助
问题解决:Type 'string' is not assignable to type 'mimeType'
我定义了如下TypeScript自定义类型:
export type Extensions = | '.gif' | '.png' | '.jpeg' | '.jpg' | '.svg' | '.txt' | '.jpg' | '.csv' | '.zip'; export type mimeType = 'image' | 'application' | 'text'; export type FileType = { [key in mimeType]?: Extensions[]; };
在使用下面的函数时,出现错误:Type 'string' is not assignable to type 'mimeType'。我已经在解构时指定类型为[mimeType, Extensions[]],但错误依然存在,求解决办法。函数代码如下:
export const getAcceptedFileTypes = (mimeTypes: FileType) => { const acceptedTypes: Accept = {}; Object.entries(mimeTypes).forEach(([key, extensions]: [mimeType, Extensions[]]) => { if (key === 'text') { acceptedTypes['text/*'] = extensions; } else if (key === 'image') { extensions.forEach( (image) => (acceptedTypes[`image/${image.substring(1)}`] = [image]) ); } else { extensions.forEach( (application) => (acceptedTypes[`application/${application.substring(1)}`] = [ application, ]) ); } }); return acceptedTypes; };
问题原因
问题出在Object.entries的类型推断逻辑上:TypeScript默认会把对象的键推断为string类型,哪怕你明确定义了FileType的键是mimeType联合类型。直接在解构时指定类型,相当于强行把string赋值给mimeType,自然会触发类型不匹配的错误。
解决方法
方法一:给Object.entries添加类型断言
直接把Object.entries(mimeTypes)断言为[mimeType, Extensions[]][],明确告知TypeScript返回的键值对类型:
export const getAcceptedFileTypes = (mimeTypes: FileType) => { const acceptedTypes: Accept = {}; // 添加类型断言,指定键值对的具体类型 (Object.entries(mimeTypes) as [mimeType, Extensions[]][]).forEach(([key, extensions]) => { if (key === 'text') { acceptedTypes['text/*'] = extensions; } else if (key === 'image') { extensions.forEach( (image) => (acceptedTypes[`image/${image.substring(1)}`] = [image]) ); } else { extensions.forEach( (application) => (acceptedTypes[`application/${application.substring(1)}`] = [ application, ]) ); } }); return acceptedTypes; };
方法二:使用类型守卫缩小类型范围
如果不想用断言,可以在循环内部添加类型守卫,判断key是否属于mimeType的取值范围,让TypeScript自动缩小类型:
// 定义类型守卫函数,判断传入的key是否符合mimeType类型 const isMimeType = (key: string): key is mimeType => { return ['image', 'application', 'text'].includes(key); }; export const getAcceptedFileTypes = (mimeTypes: FileType) => { const acceptedTypes: Accept = {}; Object.entries(mimeTypes).forEach(([key, extensions]) => { // 先过滤不符合mimeType的key,同时让TypeScript推断key的类型为mimeType if (!isMimeType(key)) return; // 这里key会被自动推断为mimeType,无需手动指定 if (key === 'text') { acceptedTypes['text/*'] = extensions; } else if (key === 'image') { // 加可选链避免extensions为undefined时报错 extensions?.forEach( (image) => (acceptedTypes[`image/${image.substring(1)}`] = [image]) ); } else { extensions?.forEach( (application) => (acceptedTypes[`application/${application.substring(1)}`] = [ application, ]) ); } }); return acceptedTypes; };
内容的提问来源于stack exchange,提问作者user21728514
相关产品推荐
相关产品推荐

