用于转换键值对象中的对象属性的通用打字稿 [英] Typescript generic to transform object property in key value object
问题描述
排序给了我一个带有 columnName 和排序方向的对象,我想将其转换为用于 mongoose 排序的键值对象.
Sorting give me an object with columnName, and sorting direction, I would like to transform it into key value object for mongoose sorting.
返回值不匹配我不知道我遗漏了什么
The return values doesn't match I can't figure out what I'm missing
我有以下接口:
export enum SortDirection {
asc = 'asc',
desc = 'desc',
}
export class Sort<T> {
columnName: keyof T
direction: SortDirection
}
interface CriteriaRequestDto<T> {
sort: Sort<T>
}
type SortQuery<T> = {
[key in keyof T]?: SortDirection
}
buildSortQuery<T>(
criteria: CriteriaRequestDto<T>,
): SortQuery<T> {
if (!criteria || !criteria.sort) {
return {}
}
const { columnName, direction } = criteria.sort
return { [columnName]: direction }
}
推荐答案
问题来了 return { [columnName]: direction }
.
当您期望 Record
根据我的经验,TS 不能很好地处理计算对象属性.99% 将缩小为索引类型 {[prop: string]: unknown}
.
From my experience, TS does not play well with computed object properties. 99% it will be narrowed to indexed type {[prop: string]: unknown}
.
为了解决这个问题,我做了一个 record
函数,它会返回 Record
.
To fix this problem, I made a record
function which will return Record<keyof T, unknown>
.
我是怎么做到的?我只是在函数中添加了一个重载.
How I did it? I just added one overloading to the function.
这是 100% 好的解决方案吗?不,因为定义多个重载是一种很好的做法.
Is this 100% percent good solution? No, because it is a good practice to define more than one overloading.
我会说重载比类型转换(as
运算符)安全一点,但只是一点点.
I would say that overloading is a bit safer than type casting (as
operator), but only a bit.
所以我只是定义了record
函数的返回类型.
So I just defined the returned type of record
function.
function record<K extends Keys, V = unknown>(key: K, value: V): { [prop in K]: V }
function record<K extends Keys, V = unknown>(key: K, value: V) {
return { [key]: value }
}
因为下一个符号不起作用:
Because next notation does't work:
function record<K extends Keys, V = unknown>(key: K, value: V): { [prop in K]: V } {
return { [key]: value } // error
}
这里有完整的例子:
interface Cat {
age: number;
breed: string;
}
enum SortDirection {
asc = 'asc',
desc = 'desc',
}
interface Sort<T> {
columnName: keyof T
direction: SortDirection
}
interface CriteriaRequestDto<T> {
sort: Sort<T>
}
type Keys = string | number | symbol;
function record<K extends Keys, V = unknown>(key: K, value: V): { [prop in K]: V }
function record<K extends Keys, V = unknown>(key: K, value: V) {
return { [key]: value }
}
type SortQuery<T> = Partial<Record<keyof T, SortDirection>>
function buildSortQuery<T>(
criteria: CriteriaRequestDto<T>,
): SortQuery<T> {
if (!criteria || !criteria.sort) {
return {}
}
const { columnName, direction } = criteria.sort
return record(columnName, direction)
}
const sortQuery: SortQuery<Cat> = {}
sortQuery.age = SortDirection.asc // OK
const sort: Sort<Cat> = {
columnName: "age", // OK
direction: SortDirection.asc, // OK
}
const criteria: CriteriaRequestDto<Cat> = {
sort: sort //ok
}
const query = buildSortQuery<Cat>(criteria)
query.age
更新请看一看的此处.你不应该使用 as
运算符
UPDATE
Please take a look here. You should not use as
operator
这篇关于用于转换键值对象中的对象属性的通用打字稿的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!