using in the upcoming typescript 5.2

In the upcoming TypeScript 5.2, it’s planed to add a very interesting and useful feature called using. Similar functionality already exists in other languages: in C# it’s using, and in Go it’s defer. The main idea is that using allows you to automatically release a resource (by calling a special method for this) after it exits the scope of the block. For example, if we have a method getResource that has implemented the method [Symbol.dispose](), then we can write the following code and the Symbol.dispose method will be executed automatically at the end of the main function, as if this construct were wrapped in a try finally block. ...

June 27, 2023 · 1 min · 213 words · lexich

Writing an Adapter for Fetch API

It seems that there is no such project that does not need to make requests to the server. And it is always a good idea to write a separate abstraction to describe such communication. This not only adds readability and reusability to the code, but also makes it possible to quickly and efficiently write tests for such functionality. class NetworkService { constructor(private readonly fetch: typeof fetch) {} getUser: (): Promise<IUser> => this.fetch('/api/user').then(d => d.json()) } function getUsername(api: Pick<NetworkService, 'getUser'>) { return api.getUser().then(user => user.name); } test('getUsername', async () => { const name = await getUsername({ getUser: () => Promise.resolve({ name: 'test' } as IUser) }); expect(name).toBe('test'); }); And for an average project, this approach will be sufficient. But sometimes there are requirements that you need to redefine the fetch itself. For example, in our project, we are developing an extension for the browser and we want to make requests through the serviceWorker. And there is a requirement to reimplement the Fetch API. As we know, fetch returns a Response primitive, for the creation of which you need to pass the ReadableStream as the first argument, and the response characteristics as the second. Thus, we can use the following construction. ...

June 19, 2023 · 3 min · 437 words · lexich

Creating parameterized strings

A task that is found in almost every project is the creation of parameterized strings. Most often, such constructions can be found in routers, but application can be found in many other places. It usually looks something like this: const postURL = template('{host}/posts/{id}'); const url = postURL({ host: 'http://example.com', id: 1 }); // url === 'http://example.com/posts/id' Implementing such an API is not a big deal. We split the string using a regular expression, substituting real values for variables. // create regexp for splitting const buildSeparatorVarRx = (start: string, end: string) => new RegExp(`${start}([^${start + end}]+)${end}`); // use brackets as a separator const rx = buildSeparatorVarRx('\\{', '\\}'); export function template(tmpl: T) { const array = tmpl.split(rx); // TTemplateFunction - ??? const fn: TTemplateFunction = args => array.map((item, i) => (i % 2 ? (args as Record)[item] : item)).join('') as any; return fn; } This implementation meets all our needs, but the question remains what is TTemplateFunction? It constructs a function type from a literal string (string literal types) T, which is passed an object whose keys must match the variables from type T. The return value will be a literal string with substituted values from the arguments instead of the variables from T. ...

June 4, 2023 · 4 min · 774 words · lexich

Java-style DI in TypeScript

At work, we encountered a fairly common architectural problem in our project. We have a set of services that depend on each other. Initially, the relationships between the services were described using DI through the constructor. interface Options { service1: Service1; service2: Service2; serviceN: ServiceN; } class ServiceNew { constructor(private options: Options) {} } In most cases, this approach is quite effective. However, sometimes there are situations, for example, when two services depend on each other and you have to inject the dependency through getter functions. ...

May 31, 2023 · 2 min · 399 words · lexich

The Subscriber Pattern in MobX

The last time I wrote about createAtomSubscriber and told you about its extreme usefulness. I propose to write a Subscriber primitive for reactive subscription/unsubscription/resubscription to data sources. Let’s start with an example of using such a construction. Imagine that we have a receiveData function that generates data after passing it a text id and a reactive variable $id. Using Subscriber we will create a reactive subscription. When getId returns a value other than undefined and subscriber.data is under observation, receiveData will be started and, using push, we will save the last received value. When the value returned by getId changes (it is important that it is reactive), the subscription will be canceled. If the new value is not undefined, then a resubscription will occur. When subscriber.data goes out of observation, an unsubscription always occurs, regardless of getId. ...

May 22, 2023 · 3 min · 455 words · lexich