PROG_WAY_BLOG Telegram 286
Как типизировать функцию мемоизации

В прошлом посте я разбирал реализацию функции мемоизации на JavaScript и упомянул, что типов там нет осознанно. В этом посте мы отдельно разберём типизацию такой функции, это будет полный разбор для самых маленьких.

Шпаргалка по используемым в посте utility-типам:

Parameters<T> - возвращает тип аргументов функции T
ReturnType<T> - возвращает тип возвращаемых значений функции T

const foo = (a: number , b: number) => 5

type Args = Parameters<typeof foo>
// [a: number, b: number]

type Return = ReturnType<typeof foo>
// number


Итак, наша функция принимает в себя другую функцию. Сразу же типизируем это:

function memoize(func: (...args: any[]) => any) {
// ...
}


Далее было бы неплохо типизировать возвращаемую функцию. Для этого мы можем использовать следующую конструкцию: (...args: Parameters<оригинальная функция>) => ReturnType<оригинальная функция>. И вот мы сталкиваемся с проблемой, что для корректной типизации возвращаемой функции нам необходимы типы Parameters и ReturnType, которые обязательно принимают дженерик. В качестве дженерика выступает тип оригинальной функции. Для удобства вынесем тип оригинальной функции в дженерик функции memoize:

function memoize<T extends (...args: any[]) => any>(func: T) {
// ...
}


И итоговый интерфейс функции у нас сильно растянется, но будет таким:

type AnyFunction = (...args: any[]) => any;
type MemoizedFunction<T extends AnyFunction> =
(...args: Parameters<T>) => ReturnType<T>

function memoize<T extends AnyFunction>(func: T): MemoizedFunction {
// ...
}


Ребята, стараюсь максимально упростить. Если плохо понимаете дженерики, постарайтесь более внимательно вчитываться в код.

Далее типизация кэша, тут всё просто:

const cache = new Map<string, ReturnType<T>>();


По типизации, ключ — строка, а значение — тот тип, который возвращает оригинальная функция.

Далее рассмотрим итоговый код:

type AnyFunction = (...args: any[]) => any;
type MemoizedFunction<T extends AnyFunction> =
(...args: Parameters<T>) => ReturnType<T>

function memoize<T extends AnyFunction>(func: T): MemoizedFunction {
const cache = new Map<string, ReturnType<T>>();

return function(...args: Parameters<T>): ReturnType<T> {
const key = JSON.stringify(args);

if (!cache.has(key)) {
cache.set(key, func(...args));
}

return cache.get(key)!;
};
}


Надеюсь вышло понятно. Если что, любые вопросы можем обсудить в комментариях.

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #code #typescript
🔥24👍6🤯32🐳1



tgoop.com/prog_way_blog/286
Create:
Last Update:

Как типизировать функцию мемоизации

В прошлом посте я разбирал реализацию функции мемоизации на JavaScript и упомянул, что типов там нет осознанно. В этом посте мы отдельно разберём типизацию такой функции, это будет полный разбор для самых маленьких.

Шпаргалка по используемым в посте utility-типам:

Parameters<T> - возвращает тип аргументов функции T
ReturnType<T> - возвращает тип возвращаемых значений функции T

const foo = (a: number , b: number) => 5

type Args = Parameters<typeof foo>
// [a: number, b: number]

type Return = ReturnType<typeof foo>
// number


Итак, наша функция принимает в себя другую функцию. Сразу же типизируем это:

function memoize(func: (...args: any[]) => any) {
// ...
}


Далее было бы неплохо типизировать возвращаемую функцию. Для этого мы можем использовать следующую конструкцию: (...args: Parameters<оригинальная функция>) => ReturnType<оригинальная функция>. И вот мы сталкиваемся с проблемой, что для корректной типизации возвращаемой функции нам необходимы типы Parameters и ReturnType, которые обязательно принимают дженерик. В качестве дженерика выступает тип оригинальной функции. Для удобства вынесем тип оригинальной функции в дженерик функции memoize:

function memoize<T extends (...args: any[]) => any>(func: T) {
// ...
}


И итоговый интерфейс функции у нас сильно растянется, но будет таким:

type AnyFunction = (...args: any[]) => any;
type MemoizedFunction<T extends AnyFunction> =
(...args: Parameters<T>) => ReturnType<T>

function memoize<T extends AnyFunction>(func: T): MemoizedFunction {
// ...
}


Ребята, стараюсь максимально упростить. Если плохо понимаете дженерики, постарайтесь более внимательно вчитываться в код.

Далее типизация кэша, тут всё просто:

const cache = new Map<string, ReturnType<T>>();


По типизации, ключ — строка, а значение — тот тип, который возвращает оригинальная функция.

Далее рассмотрим итоговый код:

type AnyFunction = (...args: any[]) => any;
type MemoizedFunction<T extends AnyFunction> =
(...args: Parameters<T>) => ReturnType<T>

function memoize<T extends AnyFunction>(func: T): MemoizedFunction {
const cache = new Map<string, ReturnType<T>>();

return function(...args: Parameters<T>): ReturnType<T> {
const key = JSON.stringify(args);

if (!cache.has(key)) {
cache.set(key, func(...args));
}

return cache.get(key)!;
};
}


Надеюсь вышло понятно. Если что, любые вопросы можем обсудить в комментариях.

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат — #code #typescript

BY progway — программирование, IT


Share with your friend now:
tgoop.com/prog_way_blog/286

View MORE
Open in Telegram


Telegram News

Date: |

Today, we will address Telegram channels and how to use them for maximum benefit. The Channel name and bio must be no more than 255 characters long In the “Bear Market Screaming Therapy Group” on Telegram, members are only allowed to post voice notes of themselves screaming. Anything else will result in an instant ban from the group, which currently has about 75 members. How to Create a Private or Public Channel on Telegram? Some Telegram Channels content management tips
from us


Telegram progway — программирование, IT
FROM American