TypeScript点击Add Task报o.error is not a function错误
TypeScript待办应用
Uncaught TypeError: o.error is not a function报错排查 问题场景
TypeScript初学者开发简易待办清单应用,目标是创建待办对象存入数组,后续基于数组渲染待办项到DOM。点击Add Task按钮时触发报错,相关代码如下:
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ts-todo</title> <link rel="stylesheet" href="../src/index.css"> </head> <body> <main> <input type="text" name="todo" id="input" value="" > <button id="add-btn">Add Task</button> <ul id="todo"> </ul> </main> <script src="./bundle.js"></script> </body> </html>
TypeScript代码
import { uuid } from "uuidv4" // const ul = document.querySelector("#todo")as HTMLUListElement const button = document.querySelector('#add-btn') as HTMLButtonElement const input = document.querySelector("#input") as HTMLInputElement // 存储待办对象的数组 let todos: object[] = [] interface Todos { id: string; todo: string; completed: boolean; readonly createdDate: Date; updatedDate?: Date; } let storeObject = (todo: string)=>{ const item: Todos = { id: uuid(), todo: todo, completed: false , createdDate: new Date, } todos.push({item}) console.log('todos',todos); } button.addEventListener("click",(e)=>{ console.log('enters in listener') if(input.value == "") return storeObject(input.value) input.value = "" })
Webpack配置
const path = require('path'); const NodePolyfillPlugin = require("node-polyfill-webpack-plugin") module.exports = { entry: './src/index.ts', devtool: 'inline-source-map', watch:true, module: { rules: [ { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/, }, ], }, plugins: [ new NodePolyfillPlugin() ], resolve: { extensions: ['.tsx', '.ts', '.js'], }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, };
报错根因
报错和待办业务逻辑无关,完全是第三方依赖兼容问题导致:
- 项目使用的老旧版本
uuidv4包对ES Module导入、浏览器环境的适配存在缺陷,配合NodePolyfillPlugin做Node API polyfill时,包内部的日志调用代码被webpack压缩混淆后,无法找到对应的console.error方法,最终抛出o.error is not a function的类型错误。 - 现有业务代码还存在三个隐藏问题,后续渲染时会触发异常:
todos数组标注类型为object[],丢失了自定义Todos接口的类型校验能力- 存储待办时写了
todos.push({item}),会把合法的待办对象额外包一层item属性,后续读取id、待办文本时会拿到undefined new Date未加执行括号属于不规范写法,虽然不会直接报错,但在部分环境下会出现异常返回值
修复方案
- 替换存在兼容问题的依赖:卸载老旧的
uuidv4包,换成官方维护、原生支持TS与浏览器环境的uuid库,执行以下命令:
npm uninstall uuidv4 npm install uuid npm install -D @types/uuid
- 修改TypeScript代码,修正导入、类型定义、存储逻辑的问题:
// 替换原有uuidv4的导入 import { v4 as uuidv4 } from 'uuid'; // 提前获取后续渲染需要的列表节点 const button = document.querySelector('#add-btn') as HTMLButtonElement const input = document.querySelector("#input") as HTMLInputElement const ul = document.querySelector("#todo") as HTMLUListElement // 数组类型使用自定义Todos接口,获得完整类型校验 let todos: Todos[] = [] interface Todos { id: string; todo: string; completed: boolean; readonly createdDate: Date; updatedDate?: Date; } let storeObject = (todo: string)=>{ const item: Todos = { id: uuidv4(), todo: todo, completed: false, createdDate: new Date(), // 补全Date的执行括号 } // 直接存储待办对象,去掉多余的对象包裹 todos.push(item) console.log('todos', todos); } button.addEventListener("click", ()=>{ if(input.value.trim() === "") return storeObject(input.value.trim()) input.value = "" })
- 如果项目没有使用其他Node核心模块API,可以移除webpack配置中的
NodePolyfillPlugin,减少不必要的polyfill注入,降低兼容问题出现概率。 - 重新执行webpack打包,点击Add Task按钮即可正常生成待办对象存入数组,控制台不会再抛出原有类型错误。
内容的提问来源于stack exchange,提问作者Mubashir Waheed
相关产品推荐
相关产品推荐

