Currying est une technique de programmation fonctionnelle qui transforme une fonction avec plusieurs arguments en une séquence de fonctions, chacune prenant un seul argument. Cette approche est particulièrement utile pour créer des fonctions plus modulaires et réutilisables, permettant une application partielle des arguments. Dans TypeScript, l'implémentation d'une fonction curry efficace nécessite une gestion minutieuse des types, en particulier lorsqu'il s'agit d'un nombre variable d'arguments.
Dans cet article, nous explorerons deux implémentations différentes d'une fonction curry dans TypeScript. Le premier utilise des interfaces avec des types statiques, tandis que le second adopte une approche plus flexible utilisant une interface unique avec des types variadiques. Nous analyserons les différences entre ces deux implémentations et discuterons des avantages de l’approche plus optimisée.
Dans la première implémentation, j'ai défini une série d'interfaces pour gérer les fonctions au curry avec un nombre variable d'arguments. Chaque interface correspond à une fonction avec un nombre précis d'arguments :
interface CurryFunction1{ (arg1: T1): R; } interface CurryFunction2 { (arg1: T1): CurryFunction1 ; } interface CurryFunction3 { (arg1: T1): CurryFunction2 ; } interface CurryFunction4 { (arg1: T1): CurryFunction3 ; } interface CurryFunction5 { (arg1: T1): CurryFunction4 ; } interface CurryFunction6 { (arg1: T1): CurryFunction5 ; }
La fonction curry est définie pour utiliser ces interfaces pour curry des fonctions avec jusqu'à six arguments :
function curry(fn: (arg1: T1, arg2: T2) => R): CurryFunction2 ; function curry (fn: (arg1: T1, arg2: T2, arg3: T3) => R): CurryFunction3 ; function curry (fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => R): CurryFunction4 ; function curry (fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5) => R): CurryFunction5 ; function curry (fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6) => R): CurryFunction6 ; function curry(fn: Function) { return function curried(...args: any[]) { if (args.length >= fn.length) { return fn(...args); } else { return (...args2: any[]) => curried(...args, ...args2); } }; }
Cette fonction est ensuite testée pour s'assurer qu'elle fonctionne correctement avec différents nombres d'arguments :
function testCurry() { const add = (a: number, b: number) => a b; const curriedAdd = curry(add); assert(curriedAdd(1)(2) === 3, 'Test curry function with 2 arguments'); const add3Args = (a: number, b: number, c: number) => a b c; const curriedAdd3Args = curry(add3Args); assert(curriedAdd3Args(1)(2)(3) === 6, 'Test curry function with 3 arguments'); }
Bien que cette implémentation soit claire et typique de TypeScript, elle présente certaines limites. Cela nécessite notamment la définition de plusieurs interfaces pour chaque nombre possible d’arguments, ce qui rend le code redondant et plus difficile à maintenir. De plus, gérer plus de six arguments nécessiterait l’ajout de plus d’interfaces, ce qui augmenterait la complexité.
Pour optimiser la fonction curry, j'ai adopté une approche plus dynamique utilisant une seule interface générique avec des types variadiques. Cette approche permet de gérer un nombre arbitraire d'arguments sans avoir besoin de définir une interface distincte pour chaque cas.
Dans cette version optimisée, la fonction curry est implémentée à l'aide d'une seule interface générique qui exploite les types variadiques de TypeScript pour gérer un nombre arbitraire d'arguments :
type CurryFunction= T extends [infer A, ...infer Rest] ? (arg: A) => CurryFunction : R; function curry (fn: (...args: T) => R): CurryFunction { return function curried(...args: unknown[]): unknown { if (args.length >= fn.length) { return fn(...args as T); } else { return (...args2: unknown[]) => curried(...([...args, ...args2] as unknown[])); } } as CurryFunction ; }
Complexité réduite : en utilisant une seule interface générique CurryFunction, cette implémentation élimine le besoin de créer plusieurs interfaces pour chaque nombre possible d'arguments. Cela rend le code plus concis et plus facile à maintenir.
Prise en charge d'un nombre arbitraire d'arguments : L'exploitation des types variadiques permet à cette fonction d'étudier des fonctions avec n'importe quel nombre d'arguments sans modifier l'implémentation. La fonction est ainsi plus flexible et adaptable à différents scénarios.
Saisie améliorée : la saisie dynamique permet à TypeScript de déduire avec précision les types d'arguments, fournissant une vérification de type plus forte pendant le développement, réduisant le risque d'erreurs et améliorant l'achèvement du code.
Cette version de la fonction curry est également testée pour garantir son bon fonctionnement :
function testCurry() { const add = (a: number, b: number) => a b; const curriedAdd = curry(add); assert(curriedAdd(1)(2) === 3, 'Test curry function with 2 arguments'); const add3Args = (a: number, b: number, c: number) => a b c; const curriedAdd3Args = curry(add3Args); assert(curriedAdd3Args(1)(2)(3) === 6, 'Test curry function with 3 arguments'); const add4Args = (a: number, b: number, c: number, d: number) => a b c d; const curriedAdd4Args = curry(add4Args); assert(curriedAdd4Args(1)(2)(3)(4) === 10, 'Test curry function with 4 arguments'); }
L'optimisation de la fonction curry dans TypeScript montre comment une approche basée sur des interfaces statiques peut être améliorée en adoptant des types variadiques. La nouvelle implémentation réduit non seulement la complexité du code, mais offre également une plus grande flexibilité et une vérification de type plus renforcée. Cet exemple souligne l'importance d'exploiter pleinement les capacités de TypeScript pour créer un code plus propre, plus modulaire et maintenable.
La transition d'une structure avec plusieurs interfaces à une seule interface générique est un excellent exemple de la façon dont la compréhension et l'application des concepts TypeScript avancés peuvent conduire à des solutions plus élégantes et efficaces.
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3