我正在尝试构建一个类型安全的查询系统,它看起来有点像 MongoDB 查询。
我想保证一个对象具有联合类型的单个属性,但找不到解决方案。有人可以帮我编译下面的代码吗?
type Operator = 'AND' | 'OR';
type OperatorNode = { [O in Operator]: [] };
const shouldWork1: OperatorNode = {
AND: [],
};
const shouldWork2: OperatorNode = {
OR: [],
};
const shouldFail1: OperatorNode = {};
const shouldFail2: OperatorNode = {
AND: [],
OR: [],
};
Run Code Online (Sandbox Code Playgroud)
据我了解,由于结构类型的原因,这可能很难实现,但也许有技巧?
你想要的最终类型是这样的:
type OperatorNode = { AND: []; OR?: undefined; } | { OR: []; AND?: undefined; }
Run Code Online (Sandbox Code Playgroud)
也就是说,类型的联合,每个类型都有一个定义的属性,其余的属性只有undefined在它们存在时才被允许存在。您可以验证这是否按您的预期工作:
const shouldWork1: OperatorNode = { AND: [], }; // okay
const shouldWork2: OperatorNode = { OR: [], }; // okay
const shouldFail1: OperatorNode = {}; // error!
const shouldFail2: OperatorNode = { AND: [], OR: [], }; // error!
Run Code Online (Sandbox Code Playgroud)
以编程方式转换Operator为OperatorNode. 以下是我的处理方式:
type ExclusiveRecord<K extends PropertyKey, V> = {
[P in K]: Record<P, V> & Partial<Record<Exclude<K, P>, never>> extends
infer O ? { [Q in keyof O]: O[Q] } : never }[K]
Run Code Online (Sandbox Code Playgroud)
这使用一些映射类型来迭代PunionK和constructs 的每个元素Record<P, V> & Partial<Record<Exclude<K, P>, never>>。Record<P, V>装置它具有P与值的密钥V,和Partial<Record<Exclude<K, P>, never>>用于在每一个密钥的装置K不包括P,它没有定义的值。有点关于extends infer O...只是将那个丑陋的交叉点变成单个对象类型,因此不必被迫处理Record<"AND", []> & Partial<Record<"OR", never>>. 然后这些最终都结合在一起。让我们确保它有效:
type OperatorNode = ExclusiveRecord<Operator, []>
/* type OperatorNode = {
AND: [];
OR?: undefined;
} | {
OR: [];
AND?: undefined;
}
*/
Run Code Online (Sandbox Code Playgroud)
是的,看起来不错。希望有所帮助;祝你好运!
| 归档时间: |
|
| 查看次数: |
109 次 |
| 最近记录: |