将递归数组/对象作为 TypeScript 中的扁平对象类型返回 [英] Return recursive array/object as flattened object type in TypeScript

查看:47
本文介绍了将递归数组/对象作为 TypeScript 中的扁平对象类型返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个函数,该函数采用递归对象/数组,其中每个节点都有一个名称",并且可以选择子节点".然后我想要一个函数,它采用这种递归结构并返回一个类型安全的对象,其中递归出现的名称"是键,节点是值;因此,如果您尝试访问不存在的密钥,它会在编译期间为您出错.

I'm trying to write a function that takes a recursive object/array where each node has a "name", and optionally, "children". I would like to then have a function which takes this recursive structure and return a type-safe object where the recursively occurring "name"s are the keys, and the node is the values; so it would error out for you during compile time if you tried to access a key that didn't exist.

到目前为止,我能够以这种方式识别顶级名称(名称a"和b"),因此 flat 将被识别为 Record<";一个"|b",RouteConfigItem.

So far I was able to get the top-level names recognized this way (names "a" and "b") so that flat would be recognized as Record<"a" | "b", RouteConfigItem<"a" | "b">>.

type RouteConfigItem<Keys> = {
    name: Keys;
    path: string;
    children?: Array<RouteConfigItem<Keys>>;
}

type RouteConfig<Keys> = RouteConfigItem<Keys>[];

function getFlat<Keys>(routeConfig: RouteConfig<Keys>): Record<Keys, RouteConfigItem<Keys>> {
    // Implementation doesn't matter.
    return routeConfig as Record<Keys, RouteConfigItem<Keys>>;
}

const flat = getFlat([{
    name: 'a',
    path: 'a',
}, {
    name: 'b',
    path: 'b',
    children: [{
        name: 'c',
        path: 'c',
    }]
}] as const);

但是我怎么能让它也看到非顶级名称呢?只关心类型,不关心getFlat()主体中的实现,我希望flat被识别为 记录a"|b"|c",RouteConfigItem.

But how could I make it also see the non-top-level names as well? Only caring about the types, not the implementation in the body of getFlat(), I would like for flat to be recognized as Record<"a" | "b" | "c", RouteConfigItem<"a" | "b" | "c">>.

顺便说一下,代码示例在我的 WebStorm 中似乎对我有用,但在 typescriptlang.org/play 中似乎不起作用,所以我没有包含这样的链接.

By the way, the code example seemed to work for me in my WebStorm, but does not seem to work in typescriptlang.org/play, so I didn't include such a link.

推荐答案

我稍微简化了 RouteConfig 定义:

I've simplified a bit the RouteConfig definition:

type RouteConfig = {
    name: string, 
    path: string, 
    children?: ReadonlyArray<RouteConfig> 
};

现在要提取密钥,您可以:

Now to extract keys you can:

type ExtractKeys<R extends RouteConfig> = R extends { children: ReadonlyArray<RouteConfig> }
    ? R['name'] | ExtractKeys<R['children'][number]>
    : R['name'];

函数签名是:

function getFlat<R extends RouteConfig>(routeConfig: readonly R[]):
    Record<ExtractKeys<R>, RouteConfig> {

    // Implementation doesn't matter.
    return routeConfig as any;
}

const flat = getFlat([{
    name: 'a',
    path: 'a',
}, {
    name: 'b',
    path: 'b',
    children: [{
        name: 'c',
        path: 'c',
    }]
}] as const); // Record<"a" | "b" | "c", RouteConfig>

游乐场

这篇关于将递归数组/对象作为 TypeScript 中的扁平对象类型返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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