目錄
- 問題描述
- 嘗試的解決辦法
- 真正的解決辦法
- 結論
一、 問題描述
一個很久沒接觸的老項目,前兩天想看一下里面一個功能,結果前端起不來了。
先上報錯:
Error: node_modules/@types/lodash/common/object.d.ts:1026:46 - error TS1005: '?' expected.
1026 : K extends `${infer N extends number}` ? T[N]
~
Error: node_modules/@types/lodash/common/object.d.ts:1026:51 - error TS2536: Type 'N' cannot be used to index type 'T'.
1026 : K extends `${infer N extends number}` ? T[N]
~~~~
Error: node_modules/@types/lodash/common/object.d.ts:1031:46 - error TS1005: '?' expected.
1031 : K extends `${infer N extends number}` ? T[N]
~
Error: node_modules/@types/lodash/common/object.d.ts:1031:51 - error TS2536: Type 'N' cannot be used to index type 'T'.
1031 : K extends `${infer N extends number}` ? T[N]
~~~~
Error: node_modules/@types/lodash/common/object.d.ts:1041:46 - error TS1005: '?' expected.
1041 : K extends `${infer N extends number}`
~
用中文關鍵詞搜了一下,網上有不少類似的問題。
此項目的環境(展示與問題相關的部分):
"dependencies": {
// angular 12
"@angular/common": "~12.1.2",
"@angular/core": "~12.1.2",
// lodash
"lodash": "^4.17.21",
},
"devDependencies": {
// lodash 的 typescript 聲明
"@types/lodash": "^4.14.182",
// ts 版本
"typescript": "~4.3.2"
}
二、 嘗試的解決辦法
本小節列舉網絡中提到的解決辦法:
更新typescript版本
出處: https://blog.csdn.net/m0_69838795/article/details/140886656
出處2: https://www.cnblogs.com/yalong/p/15502222.html
npm install typescript@latest
這種辦法的問題在於,歷史項目的ts版本是不能動的,一旦ts版本變更就會有更多的組件不滿足依賴要求。
例如Angular 12 要求的版本範圍比較窄:
Error: The Angular Compiler requires TypeScript >=4.2.3 and <4.4.0 but 4.8.4 was found instead.
修改lodash版本 或 @types/lodash 版本
出處: https://cloud.tencent.com/developer/ask/sof/794816
出處2: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/69932
類似的文章中,有兩種説法:
- 更新為特定版本,如 @types/lodash@ts2.1.5
- 保持@types/lodash和lodash大版本一致
實踐證明,不行。或者説針對特殊情況下才可以,屬於碰運氣而沒有給出原理。
筆者沒有解決。
三、 真正的解決辦法
折騰了一天還沒進展的時候,筆者直接去npm找包了。
搜索lodash看到了它的本體和對應的@types:
這裏插入一個知識點,這個@types是什麼?
上鍊接:
https://www.tslang.cn/docs/handbook/declaration-files/publish...
https://jkchao.github.io/typescript-book-chinese/typings/type...
通俗的説,拿lodash舉例,lodash本體是js庫,為了在ts中使用,就對這個庫編寫一個對應的聲明文件,以便ts能夠比較好的識別這個庫。
瞭解這個原理後,我們繼續。
看看lodash的版本,沒有什麼發現。只找到了版本號和發佈時間:
https://www.npmjs.com/package/lodash?activeTab=versions
再來看@types的版本,發現了關鍵:
https://www.npmjs.com/package/@types/lodash?activeTab=versions
它是有tag的,而tag指明瞭:@types/lodash的版本和ts版本之間的匹配情況。
因此我們得出一個結論:
- 不是@types/lodash和lodash的版本對應
- 而是@types/lodash和ts的版本對應
回到本文開頭説的,我們的ts是4.3.2,因此需要找tag為4.3的版本:
4.14.198可以兼容ts4.3,於是我們安裝這個版本:
npm install @types/lodash@4.14.198
裝好之後,問題迎刃而解:
四、 結論
最後一小節,來討論一下為什麼好好的項目,同樣的依賴文件,前兩年能跑,現在什麼都沒動,為什麼就跑不了了呢?
- 我們一般稱npm中的版本為
x.y.z。 - x為大版本,x的變化會導致代碼大範圍重構
- y為中版本,y的變化會導致一些api變化
- z為小版本,z的變化通常只包含bug修復
來看看@types/lodash的小版本:
原則上,z的變化不應該造成代碼的重大改動,而上圖中:
- 4.14.198仍然保留着ts4.3的兼容
- 但只有小版本變化的4.14.202卻刪掉了ts4.3的兼容
而我們的package.json是這麼寫的:
"@types/lodash": "^4.14.182",
這裏再引入一個知識點:
- ^ 表示小版本和中版本可變,大版本不變
- ~ 表示小版本可變,中版本和大版本不可變
那這個寫法就有問題了,版本已經漂移到不知道哪裏去了。
對於@types/lodash這種小版本變化都會改變兼容性的包,比較穩妥的做法是:
- 鎖定小版本
這樣基本就解決問題了。