Improve Typescript speed when a type is any member of a map?

2024/2/27 8:43:30

E.g., I have these types:

class User extends Entity {}class Post extends Entity {}type Entities = {user: User,post: Post,// potentially hundreds more
};type EntityType = 'user' | 'post' | ...;

When I use Entities and EntityType in generics, it noticeably slows down Typescript. It takes several minutes just to display type information in VS Code. I have generic functions like:

function getEntityFromCache<T extends EntityType>(type: T, id: number): Entities[T] | null | undefined;function getEntity<T extends EntityType>(type: T, id: number): Entities[T] | null {const cachedEntity = getEntityFromCache(type, id);if (cachedEntity !== undefined) {return cachedEntity;}...
}

My understanding of why this is slow is because Entities[T] is a union of all the values of Entities, i.e. User | Post | .... TS doesn't handle unions well. To check that the return type of cached is correct, TS has to iterate through every possible value of T. I.e. if T = 'user', verify that cachedEntity is Entities['user']; if T = 'post', verify that cachedEntity is Entities['post']; and so on. It's slow because TS has to check every value of the union every time I have a generic.

In addition, rather than just comparing generics values ('user' === 'user', 'post' === 'post'), TS compares the entire entity (User === User, Post === Post). This makes it worse because the entities are complicated.

What are some ways to speed this up? Here are some ideas I have:

  1. Remove generics from the intermediate functions and make them return the base entity type, then type cast it. E.g. function getEntityFromCache(type: T, id: number): Entity | null | undefined;

  2. Somehow make TS compare the entity type string instead of comparing the entire entities.

Answer

According to TypeScript wiki page Preferring Base Types Over Unions It is worth using subtypes, rather than unions.

However, they also come with a cost. Every time an argument is passed to printSchedule, it has to be compared to each element of the union. For a two-element union, this is trivial and inexpensive. However, if your union has more than a dozen elements, it can cause real problems in compilation speed. For instance, to eliminate redundant members from a union, the elements have to be compared pairwise, which is quadratic. This sort of check might occur when intersecting large unions, where intersecting over each union member can result in enormous types that then need to be reduced. One way to avoid this is to use subtypes, rather than unions.

Reduced example from the docs:


interface A {char: 'a' | 'b' | 'c' | 'd' | 'e';
}interface B extends A {char: 'a' | 'b';
}interface C extends A {char: 'd' | 'e';
}declare function char(schedule: A): void;
http://en.ppmy.cn/q/42186.html

Related Q&A

Open Highcharts in modal window

Im working on a site where I use Highcharts quite heavily for presenting data in charts. I want to user to be able to "zoom" each chart into a modal window for better readability.I know how t…

TypeError Base64 is not a function when using Buffer.from in Node 4.3

I am debugging a lambda function locally on Node 4.3 using the standard Amazon Machine Image (linux x64)When I run the program, I get an error in a function that is meant to decode a base64 string to u…

jquery position() not working correctly in safari and chrome

Ive seen this question posed once or twice before, but never with an answer that applies to my problem (as far as I know). I have a tooltip that appears when a link is clicked. I set the position of t…

Using setTimeout() within a JavaScript class function

Is it possible to use setTimout() within a JavaScript object? Currently the animation method call is running once, it seems that the setTimeout() isnt doing its job. I have managed to get it working, …

google maps - open marker infowindow given the coordinates

I am using google maps api v3.Using javascript, how can i open the infowindow of a marker given its coordinates?

How to show 5 rows instead of default 10 rows in datatable?

My datatable looks like this:Here it is showing default 10 datas in a single page.I need to show 1 to 5 of 58 entries so i tried to put max:5 but it is not working.I need to show only 5 data and the us…

how to get the value from dropdownlist in jQuery

i have a dropdownlist in my web-page how i can get the value from the selected option of themlike<select id="selme"> <option id="a" value="1">I need it</opt…

Mongoose Not Saving Data

I am having trouble with a simple query on my database. Following this tutorial: https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4 when Model.find() is called, he receives a JSON…

Check if object is a constructor - IsConstructor

I want to check if a JavaScript value is a constructor, that is, if it has a [[Construct]] internal method.ECMAScript defines IsConstructor, which does exactly this, but its an internal operation.So I …

Google site search catch search submit and trigger function

I have a page with just a searchbox on provided by google<gcse:search></gcse:search>Now when I type in the search box and hit enter I would like to trigger my script to run as the search re…