объявление функций стрелок машинописного текста в классах с возвращаемым типом

может кто-нибудь объяснить, что на самом деле делает этот синтаксис функции?

из https://material-ui.com/components/drawers/

  const toggleDrawer = (side: DrawerSide, open: boolean) => (
    event: React.KeyboardEvent | React.MouseEvent,
  ) => {
    if (
      event.type === 'keydown' &&
      ((event as React.KeyboardEvent).key === 'Tab' ||
        (event as React.KeyboardEvent).key === 'Shift')
    ) {
      return;
    }

    setState({ ...state, [side]: open });
  };

https://www.typescriptlang.org/docs/handbook/functions.html

Я думал, что второй набор скобок определяет возвращаемый тип как тип объединения, но это не похоже на тот случай, когда event передается в функцию ниже.

Например, как:

public toggleDrawer (side: DrawerSide, open: boolean):any {

превращая это в публичный метод класса, я думаю, следующее:


  public toggleDrawer = (side: DrawerSide, open: boolean) => (
    event: React.KeyboardEvent | React.MouseEvent,
  ) => {
   ...
  }

Поэтому непонятно, почему он не использует синтаксис :return из других сигнатур методов TS.

Это какой-то причудливый синтаксис в TS со стрелочными функциями, чтобы убедиться, что this - это то, что мы хотим, экземпляр класса?


person dcsan    schedule 29.06.2019    source источник
comment
Функция высшего порядка. Функция toggleDrawer возвращает функцию типа (event) => void   -  person unional    schedule 30.06.2019


Ответы (1)


В коде используются функции высшего порядка, как предлагается в комментарии. Синтаксис действительно немного необычный, но концепция довольно проста. Это просто функции, которые «принимают одну или несколько функций в качестве аргументов» и / или «возвращают функцию в качестве своего результата». Вот некоторые примеры:

// HO that returns a function
const first = (a: number, b: number) => {
    return () => a + b;
}
const firstHo = first(21, 21);
console.log(firstHo()); // 42

// HO that takes a function
const second = (a: number, func: (b: number, c: string) => string) => {
    console.log(func(a, "Hello World"));
}
const feed = (a: number, b: string) => `${b} : ${a}`;
second(42, feed); // Hello World : 42

//HO that takes AND returns a function
const third = (a: number, func: (b: number, c: string) => string) => {
    return (d: number) => func(a + d, "Hello World");
}
const thirdHo = third(21, feed);
console.log(thirdHo(21)); // Hello World : 42

Я явно возвращаю лямбды для ясности, но любую из этих функций можно упростить до чего-то более похожего на вашу, что может быть немного сложнее понять:

(a: number, b: number) => () => a + b;

Пример в вашей ссылке делает его использование довольно понятным. В разметке вы увидите это:

onClick={toggleDrawer(side, false)}

Очевидно, вы устанавливаете здесь обработчик событий, но toggleDrawer не обработчик; это функция, которая предоставляет обработчик, поэтому это разрешает:

onClick={(event) => {...}}

Что касается вашего вопроса об использовании синтаксиса :return, я не могу сказать, почему автор сделал это таким образом, но я предполагаю, что это для простоты и удобочитаемости. Ваш пример, полностью типизированный с определенным возвратом, будет выглядеть так:

toggleDrawer = (side: DrawerSide, open: boolean) : (event: React.KeyboardEvent | React.MouseEvent) => 
    (event: React.KeyboardEvent | React.MouseEvent) => {...}

Это просто делает его загадочным, не предоставляя дополнительной информации; он просто дублирует следующий фрагмент кода, который уже дает вам подпись возвращаемой функции.


Чтобы обратиться к другому (теперь удаленному) ответу: я не верю, что он делает, это функции каррирования который «представляет собой метод перевода оценки функции, которая принимает несколько аргументов, в оценку последовательности функций, каждая из которых имеет один аргумент». Что вам может показаться интересным, так это то, что функция, которая картирует другую функцию, сама по себе является функцией высшего порядка! Вот слишком упрощенный пример:

// add just adds three numbers
const add = (a: number, b: number, c: number) : number => a + b + c;

// curry takes a function that takes three numbers and returns a number
// and returns a series of functions that each take a single number which
// eventually calls the given function passing the three numbers in
const curry = (f: (a: number, b: number, c: number) => number) => 
    (a: number) => (b: number) => (c: number) => f(a, b, c);

const curriedAdd = curry(add);
const addOneTo = curriedAdd(1);
const addThreeTo = addOneTo(2);
const seven = addThreeTo(4);
console.log(seven); // 7
// You could also call it like so, though it makes currying pointless
console.log(curriedAdd(1)(2)(4)); // 7

Обе эти техники поначалу кажутся эзотерическими, но обе они очень мощные, и вы, вероятно, используете одну или обе в повседневной жизни. Например, filter, map и forEach - все функции высшего порядка. Вы передаете свою predicate функцию в filter, и алгоритм успешно применяет ее к каждому элементу в вашем массиве. filter заботится только о том, чтобы ваш предикат принимал элемент и возвращал логическое значение. При желании ваш предикат может быть каррированной функцией.

person ChiefTwoPencils    schedule 30.06.2019
comment
вау, это отличный подробный ответ, спасибо, что нашли время. Я думал, что увидел здесь еще один ответ, что это каррирование, а НЕ HOF, но похоже, что он был удален ... - person dcsan; 01.07.2019