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: |

Telegram iOS app: In the “Chats” tab, click the new message icon in the right upper corner. Select “New Channel.” To upload a logo, click the Menu icon and select “Manage Channel.” In a new window, hit the Camera icon. Informative To edit your name or bio, click the Menu icon and select “Manage Channel.”
from us


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