将记录路径导出为元组,仅当它们指向标量时 [英] Derive record paths as tuples, only if they point to a scalar

查看:20
本文介绍了将记录路径导出为元组,仅当它们指向标量时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于此记录:

type SomeRecord = {a: {a1: 'a1', a2: 'a2'}, b: {b1: 'b1'}}

如何仅导出指向标量的路径,以便我们最终得到:

How to only derive the paths that point to scalars, so that we may end up with:

type RecordPathsThatPointToScalars  
    = ['a', 'a1']
    | ['a', 'a2']
    | ['b', 'b1'];

标量可能是:

type Scalar = string | number | boolean

推荐答案

我的其他答案 提到了这一点,但我会重申:这种类型的函数是以一种 TypeScript 并不真正支持的方式递归的.它工作......直到它不工作(例如,编译器陷入困境或报告循环错误).所以我真的不建议在任何生产代码库中使用它.

My other answer mentions this but I will reiterate: this sort of type function is recursive in a way that isn't really supported by TypeScript. It works... until it doesn't work (e.g., the compiler gets bogged down or reports circularity errors). So I don't really recommend using this in any production code base.

无论如何,我可以将另一个答案的 Paths 定义修改为 Paths 这给出了表示对象中关键路径的元组的联合T 类型,其中该路径指向的值可分配给 V 类型.所以 PathsPaths 应该给出所有的路径,而 Paths 应该给你指向标量"的路径价值.

Anyway, I can modify the other answer's Paths<T> definition to be Paths<T, V> which gives a union of tuples representing key paths in an object of type T where the value pointed to by that path is assignable to type V. So Paths<T, unknown> or Paths<T, any> should give all the paths, while Paths<T, string | number | boolean> should give you paths that point to "scalar" values.

这是:

type Cons<H, T> = T extends readonly any[] ?
    ((h: H, ...t: T) => void) extends ((...r: infer R) => void) ? R : never
    : never;

type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
    11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...0[]]

type Paths<T, V = unknown, D extends number = 10> = [D] extends [never] ? never :
    (T extends V ? [] : never) | (T extends object ? {
        [K in keyof T]-?: Cons<K, Paths<T[K], V, Prev[D]>>
    }[keyof T] : never);

这个想法是它遍历对象(默认情况下最大深度为 10 左右),并收集所有路径,但只输出类型可分配给 V.

The idea is that it walks down through the object (up to some maximum depth of 10 or so, by default), and collects all the paths, but only outputs ones where the type is assignable to V.

如果 SomeRecord 是这个:

type SomeRecord = {
    a: { a1: 'a1', a2: 'a2' }, b: { b1: 'b1' },
    c: { foo: string, bar: symbol, baz: undefined, qux: null, quux: () => void }
}

(我在其中添加了具有某些属性的 c,其中大部分不是标量",因此应将它们排除在外),则完整路径为:

(where I've added a c with some properties, most of which are not "scalars" so they should be excluded,) then the full paths are:

type AllPaths = Paths<SomeRecord>;
// type AllPaths = [] | ["a"] | ["a", "a1"] | ["a", "a2"] | ["b"] | ["b", "b1"] | 
//  ["c"] | ["c", "foo"] | ["c", "bar"] | ["c", "baz"] | ["c", "qux"] | ["c", "quux"]

标量路径是:

type ScalarPaths = Paths<SomeRecord, string | number | boolean>;
// type ScalarPaths = ["a", "a1"] | ["a", "a2"] | ["b", "b1"] | ["c", "foo"];

看起来像你想要的,我想.

Looks like what you want, I think.

好的,希望有帮助;祝你好运!

Okay, hope that helps; good luck!

游乐场链接到代码

这篇关于将记录路径导出为元组,仅当它们指向标量时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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