我有一些可以工作的代码,但在我的IDE中总是出现打字错误。我已经精简了代码,以显示我的问题所在。
在Next.JS应用程序中,我有一个类型(TestModel
),一个用于在该模型上构建大规模查询的方法(generateTestFilter
),以及处理每个过滤条件的逻辑的其他方法(handleNameFilter
)。当尝试访问handleNameFilter
中的$and
操作符时,出于某种原因,tyescrip不喜欢这样,而如果我尝试在方法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)
}
打字Playground
2条答案
按热度按时间xytpbqjk1#
问题
Filter
的定义如下所示:-node-mongodb-ative/src/mongo_tyes.ts:67-74@5f37cb6
您可以看到它是两种类型的并集,含义如下:
1.
TSchema
上的所有属性都是可选的。1.与根过滤器操作符(其中
$and
是有效属性)相交的Map类型(太长而无法解释)。为什么
handleNameFilter
出错?由于该类型是一个联合,默认情况下,您只能访问对该联合的每个成员都有效的属性/方法。在
handleNameFilter
中,您尝试访问$and
。该属性仅出现在并集的后半部分,而不出现在前半部分(Partial<TestModel>
)。因此,TypeScrip会引发错误。为什么
generateTestFilter
没有错误?此前,我曾写道:
由于该类型是一个联合,默认情况下,您只能访问对该联合的每个成员都有效的属性/方法。
但是,您可以将文字缩小到并集的一侧。缩小是提供打字信息,以帮助使文字更具体(又名缩小)。在
generateTestFilter
中,您已经这样做了:实际上,分配给
filter
的对象中的属性名称是$and
并不重要。重要的是,属性名称不是出现在TestModel
中的名称。由于没有一个属性与TestModel
的属性匹配,因此它不满足并集的前半部分(Partial<TestModel>
),因此类型脚本将其缩小到并集的后半部分。您可以通过更改键/值来测试这一点,以匹配TestModel
中的属性-这应该会引发错误。解决方案
既然问题已经解释好了,我们应该能够找到解决方案了。乍一看,答案似乎是以某种方式缩小了类型。然而,我想要谈的是另一个问题,我认为这是真正的根本原因。
您的
handleNameFilter
函数在类型为Filter<TestModel>
的filter
参数处接受参数,然后推送到filter
上的$and
属性。然而,并不能保证$and
一开始就会存在。$and
仅因以下原因而存在:假设在将来,您可以重构这一点并删除第一行。这会打破你的逻辑。TypeScrip会保护你不受此影响。
因此,您需要以某种方式使
$and
可用于推送。选项包括:1.强制在
filter
参数类型中存在$and
属性。不过,我不建议这样做,因为添加属性的责任最好放在函数中。因此:1.将
$and
属性添加到filter
,作为函数中逻辑的一部分。nhaq1z212#
除了@Wing的详细解释外,实施这个解决方案实际上需要一点这两个“选项”:
handleNameFilter
函数中也初始化了$and
运算符(filter
参数是Filter
,它可能还没有*)$and
成员),因为Filter
中的联合:如果参数是普通的Partial<TestModel>
,它不希望稍后在$and
运算符上添加,即,当我们将类型“转换”为使用联合的另一部分时,Type脚本不喜欢Playground链接