用于查询嵌套对象的带点符号的 Typescript 类型安全字符串
Typescript type safe string with dot notation for query nested object
我正在使用 Typescript 和 firebase,我有一个带有此功能的小型抽象层,可以根据其字段名称和值搜索唯一的文档。
where<K extends keyof (T & DocumentEntity)>(fieldName: K, operator: WhereFilterOp, value: unknown): Query<T> {
this.addCriterion(new WhereCriterion(fieldName as string, operator, value));
return this;
}
当我想查询文档底部的字段时,这很有效,例如:
型号:
order: Order = {
orderId: baseId
item: { ... }
price: { ... }
restaurant: {
restaurantId: nestedId
name: chezGaston
}
}
查询:
const order = await this.documentPersistence.findUnique(
new Query<order>().where('orderId', '==', incomingOrderId)
);
但现在我想根据嵌套对象的 id 进行查询。
const order = await this.documentPersistence.findUnique(
new Query<order>()
.where('restaurant.restaurantId', '==', integration),
);
这给了我一个静态错误TS2345: Argument of type '"restaurant.restaurantId"' is not assignable to parameter of type 'keyof Order'.
如何修复我的函数,使其接受嵌套对象作为我对象的键?
我不想用// @ts-ignore
您可以从 TypeScript 4.1 开始执行此操作。
单击 playground 示例以查看实际效果:
相关代码如下:
type PathImpl<T, K extends keyof T> =
K extends string
? T[K] extends Record<string, any>
? T[K] extends ArrayLike<any>
? K | `${K}.${PathImpl<T[K], Exclude<keyof T[K], keyof any[]>>}`
: K | `${K}.${PathImpl<T[K], keyof T[K]>}`
: K
: never;
type Path<T> = PathImpl<T, keyof T> | keyof T;
type PathValue<T, P extends Path<T>> =
P extends `${infer K}.${infer Rest}`
? K extends keyof T
? Rest extends Path<T[K]>
? PathValue<T[K], Rest>
: never
: never
: P extends keyof T
? T[P]
: never;
declare function get<T, P extends Path<T>>(obj: T, path: P): PathValue<T, P>;
const object = {
firstName: "Diego",
lastName: "Haz",
age: 30,
projects: [
{ name: "Reakit", contributors: 68 },
{ name: "Constate", contributors: 12 },
]
} as const;
get(object, "firstName"); // works
get(object, "projects.0"); // works
get(object, "projects.0.name"); // works
get(object, "role"); // type error
我正在使用 Typescript 和 firebase,我有一个带有此功能的小型抽象层,可以根据其字段名称和值搜索唯一的文档。
where<K extends keyof (T & DocumentEntity)>(fieldName: K, operator: WhereFilterOp, value: unknown): Query<T> {
this.addCriterion(new WhereCriterion(fieldName as string, operator, value));
return this;
}
当我想查询文档底部的字段时,这很有效,例如:
型号:
order: Order = {
orderId: baseId
item: { ... }
price: { ... }
restaurant: {
restaurantId: nestedId
name: chezGaston
}
}
查询:
const order = await this.documentPersistence.findUnique(
new Query<order>().where('orderId', '==', incomingOrderId)
);
但现在我想根据嵌套对象的 id 进行查询。
const order = await this.documentPersistence.findUnique(
new Query<order>()
.where('restaurant.restaurantId', '==', integration),
);
这给了我一个静态错误TS2345: Argument of type '"restaurant.restaurantId"' is not assignable to parameter of type 'keyof Order'.
如何修复我的函数,使其接受嵌套对象作为我对象的键?
我不想用// @ts-ignore
您可以从 TypeScript 4.1 开始执行此操作。
单击 playground 示例以查看实际效果:
相关代码如下:
type PathImpl<T, K extends keyof T> =
K extends string
? T[K] extends Record<string, any>
? T[K] extends ArrayLike<any>
? K | `${K}.${PathImpl<T[K], Exclude<keyof T[K], keyof any[]>>}`
: K | `${K}.${PathImpl<T[K], keyof T[K]>}`
: K
: never;
type Path<T> = PathImpl<T, keyof T> | keyof T;
type PathValue<T, P extends Path<T>> =
P extends `${infer K}.${infer Rest}`
? K extends keyof T
? Rest extends Path<T[K]>
? PathValue<T[K], Rest>
: never
: never
: P extends keyof T
? T[P]
: never;
declare function get<T, P extends Path<T>>(obj: T, path: P): PathValue<T, P>;
const object = {
firstName: "Diego",
lastName: "Haz",
age: 30,
projects: [
{ name: "Reakit", contributors: 68 },
{ name: "Constate", contributors: 12 },
]
} as const;
get(object, "firstName"); // works
get(object, "projects.0"); // works
get(object, "projects.0.name"); // works
get(object, "role"); // type error