起因 一個feature開發, 結果需求評審、工時預估, 簡直是事故級別的. 最後, 迫於無奈, 全組人都得上去救火... 今天, 幫忙改bug的時候, 發現新checkout下來的代碼, 還帶著新鮮的語法錯誤...簡直大無語. 翻了遍代碼, 發現很多地方都存在Array.reduce類型重載相關的 ...
起因
一個feature開發, 結果需求評審、工時預估, 簡直是事故級別的. 最後, 迫於無奈, 全組人都得上去救火...
今天, 幫忙改bug的時候, 發現新checkout下來的代碼, 還帶著新鮮的語法錯誤...簡直大無語.
翻了遍代碼, 發現很多地方都存在Array.reduce類型重載相關的問題, 簡單記錄一下解決過程.
排查過程
大家的vscode都不裝語法提示插件麽? 代碼掛著紅線, 就扔代碼庫了??? 抽時間, 得把hook安排上了
// 業務代碼不方便外流, 簡單寫了個demo, 問題原因相同
const nums = [1, 2, 3, 4, 5];
const sum = nums.reduce((pre, cur) => {
return [...pre, { count: cur }];
}, []);
sum.push({ count: 6 });
console.log(sum);
// 這段代碼, 編譯成.js後, 其實是可以運行的. 但如果裝了插件, 可以看到明顯的TS語法錯誤..
// 輸出值
// [
// { count: 0 },
// { count: 1 },
// { count: 2 },
// { count: 3 },
// { count: 4 },
// { count: 5 },
// { count: 6 }
// ]
(pre, cur)=>{}
會提示沒有對應的重載類型. 原因不複雜, 就是類型不符合推導預期, 但為什麼不符合預期, 還真沒仔細看過. 本著fixbug可以, 但不能一無所獲的思想, 查看了對應的TS類型聲明
// 3種reduce的類型聲明
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;
很明顯, reduce對類型的推導, 基本就是, 「參數類型」和「返回值類型」相同、且reduce前後, 只有一種類型, 那不用加「泛型」
但是, 如果出現1種以上的類型, 且preValue與initValue、returnType類型不同, 就必須顯式標註類型.
案例中, pre的類型為never[]
, cur的類型是number
, 而reduce的返回值類型是Array<{ count: number }>
. 根據之前推導的結論, 出現3種類型, 且pre與cur、return值類型不同, 必須顯式聲明類型.
根據TS的類型聲明, 有2種可用的解決方法:
- 給initValue增加類型斷言,
[] as Array<{ count: number }>
. - 在reduce處, 聲明泛型類型
nums.reduce<Array<{ count: number }>>
核心解決思路: 減少TSC推導類型的種類, 促使其符合已存在的類型定義.
吐槽
只要思想不滑坡, 辦法總比困難多
問題很直觀, 也不複雜. 但看log, 這語法問題已經存在2個月了, 真的是vscode沒裝插件麽?
本文來自博客園,作者:林十二XII
轉載請註明原文鏈接:https://www.cnblogs.com/lin-xii/p/ts-zhong-arrayreduce-ti-shi-mei-you-yu-ci-diao-yon.html