我有一些有效的代碼,但在我的 IDE 中不斷拋出 TypeScript 錯誤。我已經壓縮代碼以顯示我的問題是什么。
在 Next.JS 應用程式中,我有一個型別 ( TestModel)、一個用于在該模型上構建大量查詢的方法 ( generateTestFilter),以及處理每個過濾條件邏輯的其他方法 ( handleNameFilter)。當嘗試訪問 中的$and運算子時handleNameFilter,TypeScript 出于某種原因不喜歡這樣,而如果我嘗試在方法中訪問它generateTestFilter,這里沒有問題。知道為什么會這樣嗎?
import { Filter } from "mongodb"
export interface TestModel {
name: string,
things: string[],
stuff: number
}
function generateTestFilter(tm: TestModel) {
const filter: Filter<TestModel> = { $and: [] }
handleNameFilter(tm, filter)
if (filter.$and && filter.$and.length) { // $and can be accessed here with no issues
return filter
}
return null
}
function handleNameFilter(tm: TestModel, filter: Filter<TestModel>) {
const condition: Filter<TestModel> = {name: 'Steve'}
filter.$and.push(condition) // Property '$and' does not exist on type 'Filter<TestModel>'. Property '$and' does not exist on type 'Partial<TestModel>'.ts(2339)
}
打字稿游樂場
uj5u.com熱心網友回復:
問題
的定義Filter如下所示:
/** A MongoDB filter can be some portion of the schema or a set of operators @public */
export type Filter<TSchema> =
| Partial<TSchema>
| ({
[Property in Join<NestedPaths<WithId<TSchema>, []>, '.'>]?: Condition<
PropertyType<WithId<TSchema>, Property>
>;
} & RootFilterOperators<WithId<TSchema>>);
–節點-mongodb-native/src/mongo_types.ts:67-74 @ 5f37cb6
您可以看到它是兩種型別的并集,含義如下:
- 上的所有屬性
TSchema都是可選的。 - 與根過濾器運算子(其是有效屬性)相交的映射型別(解釋太長)。
$and
為什么中的錯誤handleNameFilter?
由于型別是聯合,默認情況下,您只能訪問對聯合的每個成員都有效的屬性/方法。在handleNameFilter您嘗試訪問$and. 該屬性只出現在并集的后半部分,而不會出現在前半部分 ( Partial<TestModel>)。因此,TypeScript 會引發錯誤。
為什么沒有錯誤generateTestFilter?
之前,我寫過:
由于型別是聯合,默認情況下,您只能訪問對聯合的每個成員都有效的屬性/方法。
但是,您可以將型別縮小到聯合的一側。Narrowing 是提供 TypeScript 資訊以幫助使型別更具體(也稱為窄)。你在generateTestFilter這里做了這個:
const filter: Filter<TestModel> = { $and: [] }
filter分配給的物件中的屬性名稱實際上并不重要$and。重要的是屬性名稱不是出現在TestModel. 由于沒有一個屬性與 的屬性匹配TestModel,因此它不滿足聯合的前半部分 ( Partial<TestModel>),因此 TypeScript 將其縮小到聯合的后半部分。您可以通過更改鍵/值以匹配其中的屬性來測驗這一點TestModel——這應該會引發錯誤。
解決方案
既然已經解釋了問題,我們應該能夠找到解決方案。乍一看,答案似乎是以某種方式縮小型別。但是,我還想解決一個額外的問題,我認為這是真正的根本原因。
function handleNameFilter(tm: TestModel, filter: Filter<TestModel>) {
const condition: Filter<TestModel> = {name: 'Steve'}
filter.$and.push(condition) // Property '$and' does not exist on type 'Filter<TestModel>'. Property '$and' does not exist on type 'Partial<TestModel>'.ts(2339)
}
您的handleNameFilter函式在輸入的引數處接收一個引數filter,Filter<TestModel>然后推送到 上的$and屬性filter。但是,不能保證$and一開始就會存在。$and只因為這個而存在:
const filter: Filter<TestModel> = { $and: [] }
handleNameFilter(tm, filter)
假設將來,您可能會重構它并洗掉第一行。這會打破你的邏輯。TypeScript 正在保護您免受這種情況的影響。
結果,您將需要以某種方式$and推送到。選項是:
- 強制引數
$and型別中屬性的存在。filter雖然,我不建議這樣做,因為添加屬性的責任最好放在函式中。所以: - 將
$and屬性添加到filter函式中作為邏輯的一部分。
uj5u.com熱心網友回復:
除了@Wing 的詳細解釋,實作該解決方案實際上需要一些“選項”:
- 如第 2 點所述,確保
$and運算子也在您的函式中初始化handleNameFilter(filter引數為 aFilter,它可能還沒有) - 我們仍然需要一點點 1(即強制
$and引數中成員的存在),因為在 : 中的聯合,Filter如果引數是一個普通的Partial<TestModel>,它不期望稍后在那個$and運算子上添加,即 TypeScript 不喜歡當我們“轉換”型別以使用聯合的另一部分
function handleNameFilter(
tm: TestModel,
// Force TS to accept adding later on the $and operator,
// otherwise it complains because the Partial<TSchema> part of the union
// does not expect it.
filter: Filter<TestModel> & { $and?: Filter<TestModel>[] }
) {
const condition: Filter<TestModel> = { name: 'Steve' }
// Make sure the $and operator is present and initialized
filter.$and ??= []
filter.$and.push(condition) // Okay
}
游樂場鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/516227.html
上一篇:如何從Angular組件中洗掉index.html中的腳本標簽
下一篇:物件是相等的,即使屬性不相等
