简体   繁体   English

Typescript 递归推断 object 值

[英]Typescript recursively infer object values

Let's say I have this AnalyticsService class假设我有这个 AnalyticsService class

export class AnalyticsService {
  static sendAnalytics(eventName: string) {
    console.log(eventName);
    // logic here...
  }

  static EVENTS = {
    Header: {
      LogoClicked: "Header: Logo Clicked",
    },
    UserMenu: {
      LoginButtonClicked: "User Menu: Login Button Clicked",
      LogoutButtonClicked: "User Menu: Logout Button Clicked",
    }
  };
}

And I use this class to send analytics like:我使用这个 class 来发送分析,例如:

AnalyticsService.sendAnalytics(AnalyticsService.EVENTS.Header.LogoClicked)

I want to extract all values of EVENTS to a union type to make sure that sendAnalytics function gets only existing event names我想将EVENTS的所有值提取到联合类型,以确保sendAnalytics function 仅获取现有事件名称

for example, the results here should be: "Header: Logo Clicked" | "User Menu: Login Button Clicked" | "User Menu: Logout Button Clicked"例如,这里的结果应该是: "Header: Logo Clicked" | "User Menu: Login Button Clicked" | "User Menu: Logout Button Clicked" "Header: Logo Clicked" | "User Menu: Login Button Clicked" | "User Menu: Logout Button Clicked"

Is it even possible with typescript? typescript 甚至可以吗?

If it is, is it going to significantly reduce the typescript performance when it's a pretty big object?如果是这样,当它是一个相当大的 object 时,它是否会显着降低 typescript 的性能?

Edit : just to clarify the EVENTS object can be really nested (I gave a tiny example just for simplicity )编辑:只是为了澄清EVENTS object 可以真正嵌套(为了简单起见,我举了一个小例子)

Here is how you could do to correctly type sendAnalytics :以下是正确键入sendAnalytics

type Keys = typeof AnalyticsService.EVENTS[keyof typeof AnalyticsService.EVENTS]

type UnionToIntersection<U> =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

type FlattenedEvents = UnionToIntersection<Keys>;

type EventNames = FlattenedEvents[keyof FlattenedEvents];

export class AnalyticsService {
  static sendAnalytics(eventName: EventNames) {
    console.log(eventName);
    // logic here...
  }

  static EVENTS = {
    Header: {
      LogoClicked: "Header: Logo Clicked",
    },
    UserMenu: {
      LoginButtonClicked: "User Menu: Login Button Clicked",
      LogoutButtonClicked: "User Menu: Logout Button Clicked",
    }
  } as const;
}

AnalyticsService.sendAnalytics(AnalyticsService.EVENTS.Header.LogoClicked); // OK
AnalyticsService.sendAnalytics('test'); // KO

TypeScript playground TypeScript操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM