У меня есть несколько карри-функций в одном месте, которые все принимают context
параметр и возвращают функцию, которая принимает один или несколько аргументов и возвращает разные типы.
Я подумал, что было бы интересно ввести context
для всех этих функций одновременно и впоследствии использовать функции withContext
. Но я не хочу потерять типизацию функций в процессе.
Это реальный код, который я пробовал:
import { map, filter } from '../controllers';
function makeProcessResult({
database,
logging,
}: ProcessResultConfig) {
return async function processResult(results: Obj[], context: ExecutionOptions) {
const [
processResultLogger,
mapWithContext,
filterWithContext,
saveResultsWithContext,
] = [
logging, // type is Loggers['processResult'] (see types)
map, // type is (context: ExecutionOptions) => (results: Obj[]) => Promise<Obj[]>
filter, // type is the same as map
database.saveProcessedResults // type is the same as map
].map(injectContext(context)); // I get the error here (pasted at the end)
// const processResultLogger = logging(context);
const mappedResults: Obj[] = await mapWithContext(results);
const filteredResults: Obj[] = await filterWithContext(mappedResults);
const savedResulst = await saveResultsWithContext(results);
processResultLogger.finalResultsSaved();
return filteredResults;
}
function injectContext<A>(context: ExecutionOptions) {
return (fn: (context: ExecutionOptions) => A) => fn(context);
}
}
Далее приведены функции и типы, которые используются в основной части:
interface Obj {
[key: string]: any
}
type LoggerFn = (...args: any) => Promise<void>
interface Loggers {
map: (ctx: ExecutionOptions) => {
transformationsLoaded: LoggerFn
mappedSuccessfully: LoggerFn
mapperFailed: LoggerFn
}
filter: (ctx: ExecutionOptions) => {
filteredByBlackList: LoggerFn
filteredSuccessfully: LoggerFn
filterFailed: LoggerFn
}
processResult: (ctx: ExecutionOptions) => {
finalResultsSaved: LoggerFn
}
}
interface Database {
}
interface ProcessResultDatabase extends Database {
saveProcessedResults: (context: ExecutionOptions) => (results: Obj[]) => Promise<Obj[]>
}
interface ProcessResultConfig {
database: ProcessResultDatabase
logging: Loggers['processResult']
}
Функции map
, filter
и database.saveProcessedResults
имеют одинаковую подпись: (context: ExecutionOptions) => (results: Obj[]) => Promise<Obj[]>
Ошибка:
Аргумент типа '(fn: (context: ExecutionOptions) => {finalResultsSaved: LoggerFn;} & ((results: Obj []) => Promise)) => {finalResultsSaved: LoggerFn; } & ((results: Obj []) => Promise <...>) 'нельзя назначить параметру типа' (значение: ((ctx: ExecutionOptions) => {finalResultsSaved: LoggerFn;}) | ((context : ExecutionOptions) => (результаты: Obj []) => Обещание), индекс: число, массив: (((ctx: ExecutionOptions) => {...;}) | ((контекст: ExecutionOptions) => (результаты : Obj []) => Обещание <...>)) []) => {...; } & ((results: Obj []) => Promise <... '. <br>Типы параметров' fn 'и' value 'несовместимы. Type' ((ctx: ExecutionOptions) => {finalResultsSaved: LoggerFn; }) | ((context: ExecutionOptions) => (results: Obj []) => Promise) «нельзя назначить типу» (context: ExecutionOptions) => {finalResultsSaved: LoggerFn;} & ((results: Obj [] ) => Обещание) '. Тип' (ctx: ExecutionOptions) => {finalResultsSaved: LoggerFn;} 'нельзя назначить типу (context: ExecutionOptions) => {finalResultsSaved: LoggerFn;} & ((результаты: Obj [] ) => Обещание) '. Тип' {finalResultsSaved: LoggerFn;} 'нельзя назначить типу {{finalResultsSaved: LoggerFn;} & ((результаты: Obj []) => Обещание)'. Тип '{finalResultsSaved: LoggerFn; } 'нельзя присвоить типу' (результаты: Obj []) => Promise '. Тип' {finalResultsSaved: LoggerFn;} 'не обеспечивает совпадения для подписи' (результаты: Obj []): Promise'.ts (2345 )
Мне было интересно, есть ли правильный способ генерировать injectContext
, поэтому он будет работать с разными т входных и возвращаемых типов?