如何通过TypeScript兼容方式获取上传文件的文件名
文件上传表单TS类型报错问题与解法
开发支持文件上传的表单时,两种获取上传文件名的写法在TS开发环境触发类型报错,编译生成的JS文件运行无异常,仅strict模式下的TS校验不通过。
基础页面结构
<form class="image-upload" method="post" enctype="multipart/form-data"> <input type="file" name="upload-file"> <input type="submit" value="Upload image"> </form>
报错场景1:基于FormData获取文件名报错
原实现代码
const form: HTMLFormElement = document.querySelector('.image-upload')! form.addEventListener('submit', (event) => { event.preventDefault() const formattedFormData = new FormData(form) const data = formattedFormData.get('upload-file')! console.log('filename: ', data['name']); // 报错位置 })
报错信息
Element implicitly has an 'any' type because expression of type '"name"' can't be used to index type 'FormDataEntryValue'. Property 'name' does not exist on type 'FormDataEntryValue'.ts(7053)
问题根因
FormDataEntryValue是字符串与File实例的联合类型,strict模式下TS要求必须做类型窄化才能访问联合类型上的专属属性。如果直接访问.name,TS无法判断当前拿到的是带name属性的File,还是不带该属性的普通字符串,因此触发类型错误。
解决方法
- 优先做安全类型窄化,运行时校验取值类型后再访问属性,无类型断言、无额外冗余代码:
form.addEventListener('submit', (event) => { event.preventDefault() const formattedFormData = new FormData(form) const data = formattedFormData.get('upload-file') // 实例校验完成类型窄化 if (data instanceof File) { console.log('filename: ', data.name); } }) - 若确认当前表单字段一定返回File对象,可直接使用TS内置的
File类型做断言,不需要自定义类型:form.addEventListener('submit', (event) => { event.preventDefault() const formattedFormData = new FormData(form) const data = formattedFormData.get('upload-file') as File console.log('filename: ', data.name) })
报错场景2:基于document.forms集合取值报错
原实现代码
const form: HTMLFormElement = document.querySelector('.image-upload')! form.addEventListener('submit', (event) => { event.preventDefault() console.log('filename: ', document.forms['image-upload']['upload-file'].files[0].name) // 报错位置 })
报错信息
Element implicitly has an 'any' type because index expression is not of type 'number'.ts(7015)
问题根因
TS内置的document.forms返回值是HTMLCollectionOf<HTMLFormElement>,该类型的定义默认仅支持数字索引访问,不支持按表单名称做字符串索引取值,因此直接用字符串当key触发strict模式校验报错。
解决方法
- 用标准DOM选择器获取元素,类型推导准确、不需要额外断言:
form.addEventListener('submit', (event) => { event.preventDefault() // 选中文件输入控件,自动推导为HTMLInputElement类型 const fileInput = form.querySelector<HTMLInputElement>('input[name="upload-file"]')! // 兼容未选文件的空值情况 console.log('filename: ', fileInput.files?.[0]?.name) }) - 若必须使用
document.forms取值,通过内置的namedItem方法拿到表单,再做对应类型断言:form.addEventListener('submit', (event) => { event.preventDefault() const targetForm = document.forms.namedItem('image-upload') as HTMLFormElement const fileInput = targetForm.elements.namedItem('upload-file') as HTMLInputElement console.log('filename: ', fileInput.files?.[0]?.name) })
项目TS配置
当前项目开启了严格类型校验:
{ "compilerOptions": { "strict": true } }
内容的提问来源于stack exchange,提问作者Pål Stakvik
相关产品推荐
相关产品推荐

