VS Code中TypeScript检查未识别await?代码运行正常却报ts(2454)错误
问题描述
我正在开发一个获取用户位置天气数据的应用,代码实际运行正常,能在控制台看到预期的API响应,但在VS Code中编写时,持续收到TypeScript错误高亮提示:
Variable 'ip_address' is used before being assigned. ts(2454)
该提示出现在await $.getJSON("https://api.ipify.org?format=json", data => {这一行。我是第一次使用TypeScript,想确认这是TypeScript扩展的识别问题,还是代码本身存在逻辑缺陷?
相关代码
TypeScript代码(app.tsx)
function array_to_comma_sep(array: Array<string>) { let output: string = String(); for (let ele of array) { output += ele + ","; } return output.substring(0, output.length-1); } class Feature { name: string; unit: string; constructor(name: string, unit: string) { this.name = name; this.unit = unit; } } type GeoLocation = { latitude: number; longitude: number; } async function getWeatherData() { const HOURLY_FEATURES: Array<Feature> = [ new Feature("temperature_2m", "celsius"), new Feature("relativehumidity_2m", "%"), new Feature("apparent_temperature", "celsius"), new Feature("precipitation_probability", "%"), new Feature("precipitation", "mm"), new Feature("snow_depth", "m"), new Feature("visibility", "m") ] // 获取用户IP地址 let ip_address: string; await $.getJSON("https://api.ipify.org?format=json", data => { ip_address = data.ip; }); // 获取用户位置 let location: GeoLocation; await $.get(`https://ipapi.co/${ip_address}/latlong/`, data => { let [lat, long]: Array<number> = data.split(",").map((num: string) => { return parseFloat(num); }); location = { latitude: lat, longitude: long } }); // 获取天气数据 let hourly_features = array_to_comma_sep(HOURLY_FEATURES.map((feat: Feature) => { return feat.name })); await $.getJSON(`https://api.open-meteo.com/v1/forecast?latitude=${location.latitude}&longitude=${location.longitude}&hourly=${hourly_features}`, data => { console.log(data); }) } getWeatherData();
HTML代码
<!DOCTYPE html> <head> <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js" integrity="sha512-3gJwYpMe3QewGELv8k/BX9vcqhryRdzRMxVfq6ngyWXwo03GFEzjsUm8Q7RZcHPHksttq7/GFoxjCVUjkjvPdw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="app.tsx" type="text/babel"></script> </head> <body> <div id="container"></div> </body>
原因分析
这个错误提示不是VS Code扩展的问题,而是TypeScript静态类型检查的正常行为。核心问题在于你使用的jQuery AJAX方法的回调写法:
虽然你给$.getJSON和$.get加了await,但当传入回调函数时,jQuery返回的并不是标准的Promise对象,TypeScript无法通过静态分析确认回调函数一定会在后续代码执行前完成变量赋值,因此判定ip_address和location可能处于未赋值状态就被使用。
而代码实际运行正常的原因是:浏览器中AJAX请求的回调会在后续同步代码执行前完成,变量最终会被赋值,但TypeScript无法预知这一运行时行为。
解决方案
方案1:使用jQuery的Promise风格写法(推荐)
jQuery的AJAX方法在不传入回调函数时,会返回一个兼容Promise的Deferred对象,此时await能正确处理异步流程,TypeScript也能准确推断变量的赋值时机:
修改后的getWeatherData函数核心代码:
async function getWeatherData() { // 保留HOURLY_FEATURES定义 // 获取用户IP地址 const ipData = await $.getJSON("https://api.ipify.org?format=json"); const ip_address = ipData.ip; // 获取用户位置 const latlongStr = await $.get(`https://ipapi.co/${ip_address}/latlong/`); const [lat, long] = latlongStr.split(",").map(num => parseFloat(num)); const location: GeoLocation = { latitude: lat, longitude: long }; // 获取天气数据 const hourly_features = array_to_comma_sep(HOURLY_FEATURES.map(feat => feat.name)); const weatherData = await $.getJSON(`https://api.open-meteo.com/v1/forecast?latitude=${location.latitude}&longitude=${location.longitude}&hourly=${hourly_features}`); console.log(weatherData); }
方案2:显式给变量赋初始值(临时规避)
如果只是想快速消除错误提示,可以给变量赋予初始值,但这只是绕过类型检查,并未解决异步流程的类型推断问题:
let ip_address: string = ""; let location: GeoLocation = { latitude: 0, longitude: 0 };
内容的提问来源于stack exchange,提问作者vs07

