用于转换键值对象中的对象属性的通用打字稿 [英] Typescript generic to transform object property in key value object

查看:45
本文介绍了用于转换键值对象中的对象属性的通用打字稿的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

排序给了我一个带有 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 }
  }

这是我在 TS Playground 上的尝试

推荐答案

问题来了 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆