生成泛型键,递归连接键并忽略对象

huangapple go评论77阅读模式
英文:

Typescript: generate generic keys recursively, concatenating keys and ignoring objects

问题

The lib Prisma accepts filters like this:

Prisma库接受这样的过滤器:

By giving the object:

通过提供对象:

I want to generate the type:

我想生成这种类型:

I managed to get this:

我成功得到了这个:

That gives me:

这给了我:
英文:

The lib Prisma accepts filters like this:

prisma.user.findMany({
     where: {
         name: { contains: 'jeff' },
         city: {
             name: { contains: 'hol' },
             state: { 
                 acr: {
                     equals: 'vegas'
                 }
             }
         }
     }
})

By giving the object:

{
    name: '',
    city: {
        name: '',
        state: {
           acr: ''
        }
    }
}

I want to generate the type:

type UserFilters = {
    name_contains?: string,
    name_equals?: string,
    city_name_contains?: string
    city_name_equals?: string
    city_state_acr_contains?: string
    city_state_acr_equals?: string
}

I managed to get this:

type FilterR<Form> = Form extends object
    ? Partial<{
            [Key in string & keyof Form as `${Key}_${'contains' | 'equals'}`]: FilterR<Form[Key]>
      }>
    : Form

That gives me:

Partial<{
    name_contains: "";
    name_equals: "";
    city_contains: Partial<{
        name_contains: "";
        name_equals: "";
        state_contains: Partial<{
            acr_contains: "";
            acr_equals: "";
        }>;
        state_equals: Partial<{
            acr_contains: "";
            acr_equals: "";
        }>;
    }>;
    city_equals: Partial<...>;
}>

答案1

得分: 1

Sure, here is the translated content:

让我们创建一个类型,它将返回具有以下形状的类型:

Record<originalKey, updatedKey>

updatedKey 将取决于原始键下的属性是否是对象。如果它是一个对象,那么我们将在更新的键的开头添加原始键和 _,然后对属性进行递归调用,否则,我们将在原始字符串的末尾添加 'contains' | 'equals'。从这个形状中,我们可以看出我们需要所有值的联合,可以使用以下类型来实现:

type ValueOf<T> = T[keyof T];

让我们为过滤器创建一个类型:

type Filter = 'contains' | 'equals';

用于获取键的类型:

type FilterKeys<T> = ValueOf<{
  [K in keyof T & string]: T[K] extends object
    ? `${K}_${FilterKeys<T[K]>}`
    : `${K}_${Filter}`;
}>;

测试:

// "name_contains" | "name_equals" | "city_name_contains" | "city_name_equals" | "city_state_acr_contains" | "city_state_acr_equals"
type A = FilterKeys<typeof obj>;

看起来不错!

剩下的就是在 映射类型 中使用这些键了:

type FilterR<T> = { [K in FilterKeys<T>]?: string };

// type A = {
//   name_contains?: string | undefined;
//   name_equals?: string | undefined;
//   city_name_contains?: string | undefined;
//   city_name_equals?: string | undefined;
//   city_state_acr_contains?: string | undefined;
//   city_state_acr_equals?: string | undefined;
// }
type A = FilterR<typeof obj>;

playground

英文:

Let's create a type that will return a type with the following shape:

Record&lt;originalKey, updatedKey&gt;

updatedKey will depend on whether the property under the original key is an object or not. If it is an object then we prepend the original key to the beginning of the updated key with _ and call the type recursively for the property, otherwise, we will add &#39;contains&#39; | &#39;equals&#39; to the end of the original string. From the shape, we can tell that we need a union of all values, which can be done with the following type:

type ValueOf&lt;T&gt; = T[keyof T];

Let's create a type for the filter:

type Filter = &#39;contains&#39; | &#39;equals&#39;;

Type for getting keys:

type FilterKeys&lt;T&gt; = ValueOf&lt;{
  [K in keyof T &amp; string]: T[K] extends object
    ? `${K}_${FilterKeys&lt;T[K]&gt;}`
    : `${K}_${Filter}`;
}&gt;;

Testing:

// &quot;name_contains&quot; | &quot;name_equals&quot; | &quot;city_name_contains&quot; | &quot;city_name_equals&quot; | &quot;city_state_acr_contains&quot; | &quot;city_state_acr_equals&quot;
type A = FilterKeys&lt;typeof obj&gt;;

Looks good!

What's left is just to use these keys in a mapped type:

type FilterR&lt;T&gt; = { [K in FilterKeys&lt;T&gt;]?: string };

// type A = {
//   name_contains?: string | undefined;
//   name_equals?: string | undefined;
//   city_name_contains?: string | undefined;
//   city_name_equals?: string | undefined;
//   city_state_acr_contains?: string | undefined;
//   city_state_acr_equals?: string | undefined;
// }
type A = FilterR&lt;typeof obj&gt;;

playground

huangapple
  • 本文由 发表于 2023年8月4日 23:06:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76837159.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定