Мое любимое предложение :( В настоящее время мы действительно можем писать this
бесплатных программ.
Для справки, предложение TC39: https://github.com/tc39/proposal-pipeline-operator
Не то, чтобы предложение еще даже не было на стадии 0. Если он когда-либо будет добавлен в семантику языка и другие детали, скорее всего, изменятся.
Я думаю, что это будет впервые (кроме некоторых старых вещей, таких как Enum и модульная система), но может ли машинописный текст, реализующий это, сделать его более заметным и повысить спрос на него в остальной части экосистемы ecma?
Просто хотел поделиться обходным путем для отсутствующего оператора конвейера, вдохновленным https://vanslaars.io/post/create-pipe-function/...
// SyncPipe with synchronous reduction
type SyncPipeMapper<T, U> = (data: T | U) => U;
type SyncPipeReducer<T, U> = (f: SyncPipeMapper<T, U>, g: SyncPipeMapper<T, U>) => SyncPipeMapper<T, U>;
type SyncPipe<T, U> = (...fns: SyncPipeMapper<T, U>[]) => SyncPipeMapper<T, U>;
function createSyncPipe<T, U>(): SyncPipe<T, U> {
const syncPipe: SyncPipeReducer<T, U> = (f: SyncPipeMapper<T, U>, g: SyncPipeMapper<T, U>) => (data: T) => g(f(data));
return (...fns: SyncPipeMapper<T, U>[]): SyncPipeMapper<T, U> => fns.reduce(syncPipe);
}
// Example:
function testSyncPipe(num: number): number {
const addOne: SyncPipeMapper<number, number> = (data: number): number => {
return data + 1;
}
const syncPipe: SyncPipe<number, number> = createSyncPipe();
const syncWaterfall: SyncPipeMapper<number, number> = syncPipe(
addOne,
addOne,
addOne,
);
// Does the equivalent of num+3
const lastnumber: number = syncWaterfall(num);
return lastnumber;
}
// AsyncPipe with asynchronous reduction
type AsyncPipeMapper<T, U> = (data: T | U) => Promise<U>;
type AsyncPipeReducer<T, U> = (f: AsyncPipeMapper<T, U>, g: AsyncPipeMapper<T, U>) => AsyncPipeMapper<T, U>;
type AsyncPipe<T, U> = (...fns: AsyncPipeMapper<T, U>[]) => AsyncPipeMapper<T, U>;
function createAsyncPipe<T, U>(): AsyncPipe<T, U> {
const asyncPipe: AsyncPipeReducer<T, U> = (f: AsyncPipeMapper<T, U>, g: AsyncPipeMapper<T, U>) => async (data: T) => g(await f(data));
return (...fns: AsyncPipeMapper<T, U>[]): AsyncPipeMapper<T, U> => fns.reduce(asyncPipe);
}
// Example:
async function testAsyncPipe(num: number): Promise<number> {
const addOne: AsyncPipeMapper<number, number> = async (data: number): Promise<number> => {
return data + 1;
}
const asyncPipe: AsyncPipe<number, number> = createAsyncPipe();
const asyncWaterfall: AsyncPipeMapper<number, number> = asyncPipe(
addOne,
addOne,
addOne,
);
// Does the equivalent of num+3
const lastnumber: number = await asyncWaterfall(num);
return lastnumber;
}
Я использую это чаще всего:
// Pipes with asynchronous reduction
type PipeMapper<T> = (data: T) => Promise<T>;
type PipeReducer<T> = (f: PipeMapper<T>, g: PipeMapper<T>) => PipeMapper<T>;
type Pipe<T> = (...fns: PipeMapper<T>[]) => PipeMapper<T>;
function createPipe<T>(): Pipe<T> {
const pipePipe: PipeReducer<T> = (f: PipeMapper<T>, g: PipeMapper<T>) => async (data: T) => g(await f(data));
return (...fns: PipeMapper<T>[]): PipeMapper<T> => fns.reduce(pipePipe);
}
// Example:
async function testPipe(num: number): Promise<number> {
const addOne: PipeMapper<number> = async (data: number): Promise<number> => {
return data + 1;
}
const pipe: Pipe<number> = createPipe();
const waterfall: PipeMapper<number> = pipe(
addOne,
addOne,
addOne,
);
// Does the equivalent of num+3
const lastnumber: number = await waterfall(num);
return lastnumber;
}
Я надеюсь, что вы найдете это полезным!
@PublicParadise слишком шаблонный :p
Хотя я определенно хотел бы увидеть какой-то вариант этого оператора в языке, предполагаемая потребность в нем исходит из двух разных ограничений ECMAScript в его нынешнем виде.
Первую очень сложно обойти или даже решить на языке: невозможность расширять встроенные объекты гигиеничным образом.
Второй, однако, вообще не нуждается в поддержке языкового уровня и может быть исправлен: стандартную библиотеку можно назвать анемичной.
Максимально Минимум — это полный провал.
Почему требуются месяцы и месяцы споров, чтобы получить Array.prototype.flatMap
в языке?
Это один метод, и он должен был быть там с самого начала, и должно быть очевидно, что его следует добавить.
Возможно, через 6 лет у Array.prototype
будет метод groupBy
.
К настоящему времени у него есть несколько реализаций Babel, которые, мы надеемся, помогут в предложении TC39:
Сейчас на 1 стадии
Итак, есть ли у этой красавицы шансы попасть в ТС? Это будет соответствовать F#. <3
Хотя есть исключения, когда предложение _важно_ для TypeScript и типов, предложения обычно не реализуются до тех пор, пока они не достигнут 3-го этапа TC39 в TypeScript, поскольку они недостаточно стабильны, чтобы гарантировать отсутствие значительных поломок и регрессий.
Хотя никто из основной команды еще не прокомментировал эту проблему, на мой взгляд, она была бы недостаточно _важной_, чтобы рассматривать ее для реализации до этапа 3. Лучше всего сосредоточиться на поддержке лидера и предложения на TC39.
Если бы только у TS была возможность просто передать этот оператор, чтобы позволить вавилону с плагинами справиться с ним.
Или иметь собственные плагины синтаксиса, как это делают post-css. Несколько лет ожидания примитивного оператора — это слишком.
@garkin : Проблема здесь в том, что TS должен понимать код, чтобы выполнять свою работу по обеспечению безопасности типов, что плохо сочетается со случайным кодом, который он не понимает. Если бы не получение макросов (#4892), в этом случае он просто скомпилировал бы код, который понимает. Но я бы пока не ожидал этого в дорожной карте, так как довольно много элементов стандартной библиотеки по-прежнему сложно набирать atm.
Теперь, когда Babel понимает машинописный текст, вы можете запустить его через Babel.
машинопись
26 октября 2017 г., 19:01, «Tycho Grouwstra» [email protected] написал:
@garkin https://github.com/garkin : проблема здесь в том, что TS должен
понимать код, чтобы выполнять свою работу по обеспечению безопасности типов, что не
хорошо сочетается со случайным кодом, который он не понимает. Если бы не получить
макросы (#4892 https://github.com/Microsoft/TypeScript/issues/4892 ), в
в этом случае он просто скомпилирует код, который он понимает. Но я бы не стал
ожидать, что в дорожной карте совсем еще нет, так как довольно много битов стандарта
библиотеке по-прежнему сложно набирать atm.—
Вы получаете это, потому что вы создали тему.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339748284 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AAZQTO6UiVHbrM6SRwaBhm8obaa3R7e9ks5swMkCgaJpZM4OzVEg
.
Теперь, когда Babel понимает машинописный текст, вы можете запустить его через Babel.
машинопись
Хотя время сборки вдвое больше :p
Было бы неплохо, если бы typescript был просто плагином Babel, тогда вам не нужно было бы
пропустить через обе программы
26 октября 2017 г., 20:16, AlexGalays [email protected] написал:
Теперь, когда Babel понимает машинописный текст, вы можете запустить его через Babel.
машинописьХотя время сборки вдвое больше :p
—
Вы получаете это, потому что вы создали тему.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339769856 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AAZQTEArBw8jj0BcZFM2yLj5ErfbtNrgks5swNqagaJpZM4OzVEg
.
@graingert : это хороший вариант, я
К сожалению, он не будет работать с API Language Service машинописного текста, который используется VisualStudioCode, Webstorm и другими IDE.
Что касается «плагинов TS», можно легко достичь желаемого результата, скажем, с помощью простого (предварительного) транспилятора для оператора канала, который понимает синтаксис TS и создает строго типизированный эквивалент оператора. Он отлично скомпилируется с проверкой типов и еще чем-то.
Конфигурация веб-пакета для этого может выглядеть примерно так:
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-pipe-operator', enforce: 'pre' },
{ test: /\.ts$/, loader: 'ts-loader' },
...
]
}
Единственная проблема, как указал @garkin , заключается в том, что служба TS не сможет сопоставить переданные части с исходным исходным файлом, тогда IDE, использующие службу, не будут работать должным образом, даже если они уже распознают оператор (ES Next синтаксис включен или что-то в этом роде).
Возможно, если мы создадим NFR (или, может быть, уже есть?) для службы TS для поддержки кумулятивных исходных карт, которые будут применяться между исходным файлом и переданным результатом, который передается компилятору, этот и другие плагины будут возможны, не затрагивая остального сообщества и, что наиболее важно, без усложнения работы основной команды.
Кроме того, я не могу сказать, насколько # 13940 связан с этим, но, по-видимому, это хорошее начало для более сложных плагинов. Однако мне кажется, что подход исходной карты по-прежнему является гораздо более простой альтернативой, поскольку минималистичный (предварительный) транспилятор в большинстве случаев не нуждается в контексте проекта, поскольку было бы довольно легко просто извлечь блоки обозначения типа (если таковые имеются) из необработанный текст оператора, а затем перепишите его таким образом, чтобы поток управления мог подразумевать определенные типы ввода-вывода для транспилируемой части.
И последнее, но не менее важное: может ли кто-нибудь указать мне на _официальную_ ветку (если таковая имеется) относительно такого рода плагинов?
Должен сказать, что я действительно ценю спокойный способ представления новых предложений и предпочитаю монолитный инструментарий Typescript и LessCSS гораздо больше, чем олимпиаду специальных плагинов Flow+Babel и Post-CSS.
Это настраиваемость и скорость получения новых функций за счет раздувания фрагментации и области знаний.
Трубщик — это как наркотик для входа в функциональный мир, он заставляет меня говорить и желать странных вещей.
Итак, #14419 и даже некоторые полезные практические выводы уже есть. Не должно быть сложно интегрировать те, у кого есть ts-loader
.
Интеграция трансформеров tsconfig.json
(и, следовательно, API языковой службы, а не только настроенная tsc
) № 14654 была отклонена _в краткосрочной перспективе_.
@PublicParadise или просто используйте flow
lodash или pipe
Rambda?
в любом случае, было бы здорово увидеть поддержку в TS. Мне нравятся функциональные шаблоны, которые поддерживает JS (особенно с выводом типа TS), но некоторые шаблоны не очень хорошо читаются. Это было бы огромно, поскольку большие библиотеки TS, такие как RxJS и IxJS, движутся к бесточечной функциональной композиции вместо расширения/наследования прототипа, это значительно улучшает встряхивание дерева и поддержку пользовательских операторов.
@felixfbecker Ты имеешь в виду pipe
Ramda? Мне нужно попробовать еще раз, но исторически сложилось так, что ramda была библиотекой JS-first, она очень динамична и сложна для ввода (например, lodash), что усугубляется тем фактом, что у TS было много проблем с выводом из возвращаемых значений функции (возможно, это было исправил недавно, но не уверен)
Я не использую lodash
как он плохо спроектирован, смешивая изменяемые и неизменяемые функции в одном большом пространстве имен.
Это на самом деле работает прилично, если ваши функции и цепочки не супер сумасшедшие:
Это на самом деле работает прилично, если ваши функции и цепочки не супер сумасшедшие.
Позвольте мне уточнить, что это «не супер сумасшедший»: все ломается, если ваши функции имеют дженерики (см. https://github.com/types/npm-ramda/issues/86), например, R.pipe(R.identity)
.
Кроме того, давайте проясним, предложение относится к Этапу 1. Основная команда становится еще более застенчивой в представлении вещей до Этапа 3. Декораторы являются частью примера. Несмотря на то, что они были помечены как _экспериментальные_, мы все пошли дальше, включили этот флаг и написали весь наш производственный код, используя их. Предложение теперь отскочило, и есть некоторые фундаментальные критические изменения в синтаксисе и семантике, которые будут означать, что нам всем придется реорганизовать наш код, что ставит основную команду в затруднительное положение, потому что, если они _только_ поддерживают окончательный синтаксис, чем у всех, ломается в тот день, когда они его выпускают, или если они сохраняют устаревшие вещи, другие изменения в компиляторе могут затруднить поддержку двух синтаксисов, и в конечном итоге вы захотите избавиться от старых вещей, но когда .. 💥 💥
Таким образом, лучшее, что можно сделать с функциями, основанными на стандартах, — это не обсуждать здесь поддержку или отсутствие поддержки TypeScript, а найти дружелюбного местного представителя TC39 и заявить, что эта функция действительно важна для вас, а также принять участие в обсуждение предложения, указанное выше, на GitHub. Чем быстрее будет разрешена семантика и чем быстрее она дойдет до стадии 3, тем быстрее у всех нас появятся хорошие вещи!
Теперь, когда в rxjs
есть допустимые операторы, это было бы еще более замечательной функцией в Typescript.
https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md
Можем ли мы попросить кого-нибудь из команды TS пролить свет на этот запрос?
Они пометили это ES Next
и Suggestion
... Я могу процитировать вам главу и стих из других мест, где они прокомментировали предложения ES Next, а также когда и как они их реализуют ...
Комментарий от них ничего не изменит. Как вы думаете, они тайно работают над этим за кулисами, ожидая, когда это станет известно сообществу? Часто не вступают в дело, если нечего добавить... К уже сказанному добавить нечего.
На данный момент я считаю, что было бы очень полезно иметь плагины, расширяющие язык. Добавление функций, которые они не будут частью ядра языка, будет частью этих плагинов.
@aminpaks Мне не очень нравится эта идея, так как она может быстро привести к бабелификации (как в Вавилонской башне, а не в превосходном транспиляторе Babeljs 😀)
Поскольку плагины подразумевают поведение на уровне типов, становится трудно понять смысл программ, а обработка зависимостей на уровне исходного кода потребует ряда сложных, но очень полезных функций, которых в настоящее время нет в TypeScript.
Как бы я ни хотел, чтобы это было везде, я рад, что TS придерживается более сдержанного подхода к реализации новых функций и придерживается стандартов. Эта позиция делает TS в целом более привлекательным для таких людей, как я, которые глубоко заботятся об отклонении от стандарта, но наслаждаются расширенными функциями, предоставляемыми транспиляцией до принятия браузером поставщика / JS-движка (но не обязательно до стандартизации). Это тонкий баланс.
Лично я не в пользу оператора конвейера в ущерб оператору привязки. Это сводится к читабельности на самом деле.
Данный:
function* where<T>(items: Iterable<T>, predicate: (item:T)=>boolean){
for (let item of items){
if(predicate(item)) yield item;
}
}
привязка-операция:
[1,2,3]::where(x=>x>2)
конвейерная операция:
[1,2,3]|>(_)=>where(_,x=>x>2)
ts-team правы, не беспокоясь до стадии 3; и даже в этом случае предложения этапа 3 могут быть отозваны (например, SIMD). Жаль, что у нас не может быть плагинов — «риск» перекладывается на отдельного разработчика. Существует множество других вариантов использования плагинов, не в последнюю очередь для поддержки таких вещей, как файлы .vue
содержащие машинописный текст.
@MeirionHughes Я согласен. Хотя я предпочел бы иметь оператор конвейера, а не вообще никакого сахара, он вдохновлен языками, в которых функции автоматически каррируются и где библиотеки построены вокруг использования этого. Также предполагается, что методы конвейера _не_ являются членами значений конвейера.
Так что тогда у вас было бы
function where<T>(predicate: (item: T) => boolean): (items: Itererable<T>) => Itererable<T> {
return function* () {
for (const item of items) if (predicate(item)) yield item;
};
}
function select<T, R>(projection: (item: T) => R): (items: Itererable<T>) => Itererable<R> {
return function* () {
for (const item of items) yield projection(item);
};
}
а то бы ты написал
[1, 2, 3] |> where(x => x > 2) |> select(x => x ** 2);
но поскольку JavaScript не выполняет и не может выполнять функции автоматического каррирования, кажется, что он хорошо работает только с библиотеками, разработанными с учетом каррирования.
Я могу ошибаться в этом, я не очень в курсе этого предложения.
Тогда новая библиотека, которая по умолчанию предоставляет каррированные функции утилиты, может стать новым стандартом: p
@AlexGalays Я думаю, что это возможно, если это пройдет. Пока это не является частью подрывного заговора по превращению JavaScript в OCaml, все в порядке.
@MeirionHughes ваш пример where
вообще не использует this
, поэтому оператор привязки не будет работать. У оператора привязки также есть много открытых вопросов по безопасности типов. Разрешено ли where
получать доступ к частным свойствам из this
как метод класса? Если нет, то какой смысл использовать this
? Если да, то изменение приватных свойств внезапно становится переломным изменением, которое полностью противоречит цели приватных свойств.
Вы также заявляете, что синтаксис менее удобочитаем, но, например, опускаете скобки в своем примере с оператором привязки, но добавляете ненужные скобки в примере с конвейером. И оператор конвейера, конечно, вообще не будет работать с функциями, написанными для связывания, но он будет хорошо работать с каррированными функциями, такими как операторы rxjs, ramda или lodash/fp.
@aluanhaddad Помимо всех библиотек fp, RxJS является примером широко используемой библиотеки, которая перешла от операторов на прототипах (у которых много проблем, в основном связанных с встряхиванием деревьев и безопасностью общих типов) к операторам в виде каррированных функций. Большинство библиотек, вероятно, не выбирают этот путь прямо сейчас, потому что у нас нет хорошего синтаксиса для него.
@felixfbecker, вы правы, и пример @aluanhaddad, в который вложены результирующие функции, которые
Кто-нибудь думал или внедряет собственный преобразователь, чтобы получить поддержку конвейера немного раньше? Судя по всему, это можно сделать с помощью пользовательского преобразователя, который просто транспилирует _просто_ саму часть конвейера. затем вы можете выполнить его через: https://github.com/cevek/ttypescript
Это возможно? Использование пользовательских преобразований для использования синтаксиса, поддерживаемого Babel, при сохранении работоспособности таких вещей, как инструменты TypeScript?
Может быть? есть предустановка, которая работает только с предложениями 0-2: https://www.npmjs.com/package/babel-preset-proposal-typescript — это означает, что вы вставляете ее перед отправкой в машинопись. Тем не менее, вы intellisense, скорее всего, будете скучать. Однако с https://github.com/cevek/ttypescript#visual -studio-code вам это может сойти с рук.
@MeirionHughes Я рад, что был полезен ❤️.
Теперь нам просто нужен #6606, чтобы мы могли преобразовать методы произвольных прототипов в каррированные функции!
TypeScript теперь представляет собой преобразование Babel, я думаю, что должен быть способ упорядочить дешугаринг конвейера перед проходом TypeScript. Я понятия не имею, как вы заставите это работать с языковым сервером.
Я добавил собственную реализацию для TS # 22816.
Как один из тех, кто настаивает на операторе конвейера, я умоляю вас: пожалуйста, _не_ реализуйте это в TypeScript, пока он не продвинется дальше. Мы все еще обсуждаем два возможных предложения, которые принципиально несовместимы друг с другом, поэтому TypeScript будет очень жалко, если реализует это слишком рано.
Если вы заинтересованы в этом предложении, взгляните на репозиторий здесь и примите участие: https://github.com/tc39/proposal-pipeline-operator/ Мы будем рады вашим отзывам! И мы работаем над плагинами Babel для различных предложений, так что у вас будет возможность опробовать их в своих (не TypeScript) проектах.
Но предложение еще не готово к использованию чего-то вроде TypeScript.
Мы определенно не объединяем это.
Можем ли мы иметь что-то вроде https://github.com/babel/babel-eslint , что позволит нам продолжать использовать функции, поддерживаемые Babel, и обеспечить работу проверки типов после того, как функции, не поддерживаемые TypeScript, будут удалены?
@masaeedu Да! Этот
@MeirionHughes с предложением частичной заявки становится проще:
[1,2,3] |> where(?, x=>x>2)
@bernatmv : между прочим, есть что-то близкое к этому, что работает сегодня.
@tycho01 Tycho01 Но не в TypeScript, пока он не наберет 2,8 набора: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/25067
@jeremejevs @bernatmv на самом деле, R.__
было набрано с помощью codegen в npm-ramda . Лучшие способы использования 2.8 приветствуются!
Я новичок в Javascript и TypeScript (2 недели), поэтому, пожалуйста, простите меня, если есть более простое решение. Но ниже то, что я придумал в отсутствие оператора конвейера. Первоначально я пытался использовать несколько перегрузок pipe
которые работали с параметрами типа 2, 3, 4 и т. д., но не мог понять, как заставить разрешение перегрузки TypeScript работать так же, как в C#. У нас могут быть разные функции pipe1<A,B>
, pipe2<A,B,C>
и pipe3<A,B,C,D>
но с ними будет сложно работать, так как вам придется выбирать имя функции на основе количества аргументов, которые вы используете. хотел. Есть ли более простое безопасное решение, чем то, что я предложил ниже? Существует ли определение рекурсивного типа, которое может принимать неограниченное количество параметров? Правильно ли я использую типы условий?
type LastOf<
A,
B=never,
C=never,
D=never,
E=never,
F=never,
G=never,
H=never,
I=never,
J=never> =
[B] extends [never] ? A :
[C] extends [never] ? B :
[D] extends [never] ? C :
[E] extends [never] ? D :
[F] extends [never] ? E :
[G] extends [never] ? F :
[H] extends [never] ? G :
[I] extends [never] ? H :
[J] extends [never] ? I :
J;
export function pipe<A, B, C=never, D=never, E=never, F=never, G=never, H=never, I=never, J=never>(
a: A,
mapA: (a: A) => B,
mapB?: (b: B) => C,
mapC?: (c: C) => D,
mapD?: (d: D) => E,
mapE?: (e: E) => F,
mapF?: (f: F) => G,
mapG?: (g: G) => H,
mapH?: (h: H) => I,
mapI?: (i: I) => J
): LastOf<A, B, C, D, E, F, G, H, I, J> {
if (mapB === undefined) {
return mapA(a) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
if (mapC === undefined) {
return mapB(mapA(a)) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
if (mapD === undefined) {
return mapC(mapB(mapA(a))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
if (mapE === undefined) {
return mapD(mapC(mapB(mapA(a)))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
if (mapF === undefined) {
return mapE(mapD(mapC(mapB(mapA(a))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
if (mapG === undefined) {
return mapF(mapE(mapD(mapC(mapB(mapA(a)))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
if (mapH === undefined) {
return mapG(mapF(mapE(mapD(mapC(mapB(mapA(a))))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
if (mapI === undefined) {
return mapH(mapG(mapF(mapE(mapD(mapC(mapB(mapA(a)))))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
return mapI(mapH(mapG(mapF(mapE(mapD(mapC(mapB(mapA(a))))))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}
test("map once", () => {
const result = pipe(
2,
i => i * 10);
expect(result).toBe(20);
});
test("map twice", () => {
const result = pipe(
2,
i => i * 10,
i => `the answer is ${i}`);
expect(result).toBe('the answer is 20');
});
test("map three times", () => {
const result = pipe(
2,
i => i * 10,
i => -i,
i => ({ a: i, b: -i }));
expect(result).toEqual({ a: -20, b: 20 });
});
Я думал, что _.flow lodash/fp уже напечатал это?
В среду, 9 мая 2018 г., 22:19 jmagaram, уведомления@github.com написал:
Я немного новичок в Javascript и TypeScript (2 недели), поэтому, пожалуйста, простите
меня, если есть более простое решение. Но ниже то, что я придумал
с при отсутствии оператора трубопровода. Я изначально пытался иметь
многократные перегрузки трубы, которые работали с 2, 3, 4 и т.д. типом
параметры, но не мог понять, как получить перегрузку TypeScript
разрешение для работы, как в C#. У нас могут быть разные функции
pipe1 , pipe2 и pipe3 , но это было бы сложно работать, так как вам придется выбирать имя функции в зависимости от того, сколькоаргументы, которые вы хотели.
Существует ли определение рекурсивного типа, которое может приниматьнеограниченное количество параметров?введите LastOf = [B] расширяет [никогда]?
Б :[D] расширяет [никогда]?
Д:[F] расширяет [никогда] ?
функциональная труба ( а: А,карта А: (а: А) => В,mapB?: (b:B) => C,mapC?: (c:C) => D,mapD?:(d:D) => E,mapE?: (e:E) => F): LastOf { const b = карта А (а);переключатель (картаB) {case undefined: вернуть b как LastOf ; дефолт: {const c = карта B (b);переключатель (mapC) {case undefined: вернуть c как LastOf ; дефолт: {const d = карта C (с);переключатель (mapD) {case undefined: вернуть d как LastOf ; дефолт: {const е = mapD(d);переключатель (карта) {case undefined: вернуть e как LastOf ;по умолчанию: вернуть mapE(e) как LastOf ; }}}}}}}}
test("сопоставить один раз", () => {
константный результат = труба (
2,
я => я * 10);
ожидать(результат).быть(20);
});test("отобразить дважды", () => {
константный результат = труба (
2,
я => я * 10,
я =>the answer is ${i}
);
ожидаем(результат).toBe('ответ равен 20');
});test("отобразить три раза", () => {
константный результат = труба (
2,
я => я * 10,
я => -я,
я => ({ а: я, б: -я }));
ожидать(результат).toEqual({a: -20, b: 20});
});—
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-387878691 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AAZQTLm6LrWe5KVx4aGBFUd4yRUHkkrZks5tw11cgaJpZM4OzVEg
.
Я только что посмотрел на lodash, и вы правы — функция потока принимает много параметров и строго типизирована. Не похоже, чтобы это было сделано на чистом TypeScript. Они используют файл определения типа для всех перегрузок. Я не уверен, что это лучше или хуже, чем пытаться сделать все это на TypeScript.
@jmagaram все TS обычно облегчают задачу благодаря умозаключениям, но если это работает, то работает.
@jmagaram Несколько более простая альтернатива машинописному тексту может выглядеть примерно так.
interface IPipe<T> {
readonly value: () => T;
chain<R>(fn: (x: T) => R): IPipe<R>;
}
function pipe<T>(val: T): IPipe<T> {
return {
chain: fn => pipe(fn(val)),
value: () => val
};
}
Использование по-прежнему будет довольно чистым и строго типизированным.
pipe(["Hello", "There"])
.chain(map(x => `${x}!`))
.chain(xs => {
...
})
.value()
Я был бы очень признателен за возможность добавлять пользовательские операторы. В F# для этого есть хороший подход.
А пока вот более простой подход без упаковки:
function pipe<T1>(first:T1):T1
function pipe<T1, T2>(first:T1, second:(a:T1) => T2):T2
function pipe<T1, T2, T3>(first:T1, second:(a:T1) => T2, third:(a:T2) => T3):T3
function pipe<T1, T2, T3, T4>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4):T4
function pipe<T1, T2, T3, T4, T5>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5):T5
function pipe<T1, T2, T3, T4, T5, T6>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6):T6
function pipe<T1, T2, T3, T4, T5, T6, T7>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6, seventh:(a:T6)=>T7):T7
function pipe<T1, T2, T3, T4, T5, T6, T7, T8>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6, seventh:(a:T6)=>T7, eigth:(a:T7)=>T8):T8
function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6, seventh:(a:T6)=>T7, eigth:(a:T7)=>T8, ninth:(a:T8)=>T9):T9
function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6, seventh:(a:T6)=>T7, eigth:(a:T7)=>T8, ninth:(a:T8)=>T9, tenth:(a:T9)=>T10):T10
function pipe(first:any, ...args:Function[]):any {
return (
args && args.length
? args.reduce(
(result, next) => next(result),
first instanceof Function ? first() : first
)
: first instanceof Function ? first() : first
);
}
Это дает:
( для получения дополнительной информации см. здесь )
Тем не менее, @graingert +1 вы правы: у lodash уже есть это для композиции (но не для канала):
const getUpperName =
_.flow(
(p: Person) => `${p.FirstName} ${p.LastName}`,
(s: string) => s.toUpper()
)
В качестве альтернативы вы можете вместо этого добавить канал в Object.prototype:
Object.prototype.pipe = function<Self, Result>(this:Self, next:(value:Self) => Result):Result {
return next(this)
}
Вместо этого это позволяет:
( для получения дополнительной информации см. здесь )
Надеюсь, это поможет другим!
Он попал в Firefox под флагом компиляции --enable-pipeline-operator
.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Pipeline_operator
Минута молчания павшему герою, оператору бинда ::
, закрытому в пользу злого |>
😢
Ну, я думаю, это в глазах смотрящего, так как я предпочитаю |>
:D
привет королю!
И тут я подумал, что это несбыточная мечта
Pipeline — это, по сути, простой вариант использования Identity Monad. Кроме того, pipe
обычно равно compose
в обратном порядке, тогда как pipeline
больше похоже на pipe
который вызывается сразу.
В любом случае, с нетерпением жду возможности увидеть это в Typescript.
Хотя наличие конвейера было бы полезно, я считаю, что было бы возможно предложить возможность определять пользовательские операторы (функции, имя которых может включать специальные символы, а первый параметр находится слева от них) через преобразователь компилятора. Кто-нибудь хочет попробовать это со мной или имеет какой-то опыт в этом?
Пт, 10 августа 2018 года, 2:53 Бабак [email protected] писал:
Pipeline — это, по сути, простой вариант использования Identity Monad. Также,
труба обычно составляется в обратном порядке, тогда как конвейер больше похож на трубу
который вызывается сразу.В любом случае, с нетерпением жду возможности увидеть это в Typescript.
—
Вы получаете это, потому что вы прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411824741 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg
.
--
Инфиксные функции ftw
Чт, 9 августа 2018 г., 23:35 Бен Битти-Худ, уведомления@github.com
написал:
Хотя наличие конвейера было бы полезно, я чувствую, что было бы возможно
предлагают возможность определять пользовательские операторы (функции, имя которых может
включают специальные символы, и чей первый параметр находится слева от них) через
трансформер компилятора. Любой, кто хочет попробовать это со мной, или уже
некоторая предыстория по этому поводу?Пт, 10 августа 2018 года, 2:53 Бабак [email protected] писал:
Pipeline — это, по сути, простой вариант использования Identity Monad. Также,
труба обычно составляется в обратном порядке, тогда как конвейер больше похож на трубу
который вызывается сразу.В любом случае, с нетерпением жду возможности увидеть это в Typescript.
—
Вы получаете это, потому что вы прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
<
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment -411824741
,
или заглушить тему
<
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg.
--
—
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411919587 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AAZQTHHFbVY5uGCWl-La_P-HF7UN6xPsks5uPLk8gaJpZM4OzVEg
.
идея инфиксных функций для машинописного текста почти так же стара, как и машинописный текст: https://github.com/Microsoft/TypeScript/issues/2319
Я знаю, что многие люди очень хотят этого, но я считаю, что TypeScript не должен реализовывать никаких дополнительных операторов, пока они не находятся на этапе 3. Все может измениться, и, конечно, есть некоторые исключения.
Я думаю, что стоит попробовать его в качестве преобразователя компилятора, просто чтобы позволить сообществу изучить идею и измерить популярность. Это четко определенная функция в других функциональных языках, поэтому ее изучение может быть вполне безопасным.
@BenBeattieHood Мы внедряем это в Babel, поэтому вы сможете протестировать его там. Если вы тестируете его в преобразователе компилятора, обязательно взгляните на текущие предложения , поскольку мы рассматриваем несколько форм оператора конвейера.
Я думаю, что нужно много думать о том, как его использовать; особенно в отношении ввода таких вещей, как:
function where<T>(predicate: (x: T) => boolean) {
return function* (items: Iterable<T>): Iterable<T> {
for (const item of items) {
if (predicate(item)) {
yield item;
}
}
};
}
[1, 2, 3] |> where(x=>x> 1)
на данный момент с where(x => x > 1)([1,2,3])
он не может сделать вывод, что такое x. приведенное выше - одна из причин, по которой я надеялся, что операция ::
победит, потому что (на первый взгляд) машинописному тексту кажется намного проще сделать вывод, что такое this
Или мы можем увидеть это по-другому: если он будет выпущен, он отдаст приоритет некоторым проблемам вывода, которые есть у TS 👍
Если вы следите за новостями спецификации и Babel, спецификация еще не установлена. Есть 2 предложения. Я уверен, что команда typescript добавит поддержку, когда спецификация будет завершена.
Инфиксные функции ftw
iirc JS называет эти «методы».
iirc JS называет эти «методы»
@ tycho01 Ваш комментарий, вероятно,
@BenBeattieHood Мы внедряем это в Babel, поэтому вы сможете протестировать его там. Если вы протестируете его в преобразователе компилятора, обязательно взгляните на текущие предложения, поскольку мы рассматриваем несколько форм оператора конвейера.
Парсер Babel теперь поддерживает предложение интеллектуального конвейера.
Любые обновления?
Любые обновления?
🤦♂️ TypeScript не реализует предложение, пока не достигнет этапа 3. Оператор конвейера в настоящее время находится на этапе 1 и имеет серьезные проблемы. Эта информация была предоставлена несколько раз в этой теме.
пример серьезных проблем, пожалуйста?
⚠ Предупреждение. Детали синтаксиса конвейера в настоящее время не решены. На рассмотрении находятся два конкурирующих предложения.
Да, это то, что я считаю серьезной проблемой.
Собираюсь заблокировать этот, так как все потоки в состоянии Ожидание TC39, как правило, просто идут по кругу.
Пинг!
Самый полезный комментарий
Сейчас на 1 стадии