Typescript: Предложение: "оператор безопасной навигации", т.е. x?.y

Созданный на 15 июл. 2014  ·  205Комментарии  ·  Источник: microsoft/TypeScript

Текущий статус

  • Предложение TC39 сейчас находится на стадии 3 (🎉🎉🎉🎉🎉)
  • Идет реализация
  • Вы можете ожидать эту функцию в TypeScript 3.7.
  • Мы обновим здесь, когда он будет доступен в ночной сборке.
  • Откладывание дополнительного вызова до тех пор, пока его семантика не будет выяснена комитетом.

Открытые вопросы

  • Какой специальный корпус, если он есть, должен получить document.all ?

C# и другие языки имеют синтаксический сахар для доступа к цепочкам свойств, где null (или, в нашем случае, undefined ) может встретиться в любой точке иерархии объектов.

var x = { y: { z: null, q: undefined } };
console.log(x?.y?.z?.foo); // Should print 'null'
console.log(x?.baz); // Still an error
console.log(x.y.q?.bar); // Should print 'undefined'

Нужно предложение о том, что именно мы должны кодировать, имея в виду побочные эффекты аксессоров.


Отредактировано @DanielRosenwasser 27 февраля 2018 г .: это предложение также называется оператором «нулевого распространения».

Committed ES Next Suggestion Update Docs on Next Release

Самый полезный комментарий

Необязательная цепочка - это этап 3

Кратковременно разблокировать этот только для праздничных целей

Все 205 Комментарий

Итак, в первом примере мы могли бы сгенерировать его следующим образом:

x && xy && xyz && xyzfoo

Но тогда нам пришлось бы каким-то образом заставить x, y, z и foo вычисляться не более одного раза.

Вы также действительно не можете сделать && во многих случаях, потому что правдивость становится проблемой для примитивов.

Например:

"     "?.trim()?.indexOf("hello")

дает "" .

Таким образом, вам нужно сделать несколько явных сравнений с null , используя == для общего случая, если только мы не используем систему типов (что было бы довольно здорово, если бы мы это сделали).

Возможно, мы могли бы создать монадическую функцию связывания (непривлекательную для вывода JS) или использовать некоторое преобразование тернарных операторов (ближе к типичному эквиваленту JS). Я явно немного предвзято отношусь к последнему.

:+1:

В идеале мы должны сначала реализовать это в ES7 (или ES8, или ES9, или...), поскольку, вероятно, возникнут некоторые разногласия по поводу точной семантики того, следует ли на самом деле использовать 0 / "" как ложные примитивы для целей любого оператора здесь.

:+1: Я бы хотел, чтобы TypeScript получил это первым, не дожидаясь ESxx.

Тот факт, что простые и безумно полезные операторы нулевой безопасности, такие как "?" и «?:» НЕТ в спецификации ES6 означает, что люди, составляющие спецификацию ES6, должны стыдливо опустить голову. Это настолько простая и очевидная вещь, что не включить ее было бы откровенно безумием. Есть причина, по которой большинство современных языков поддерживают их: они незаменимы.

Я понимаю, что это было бы отклонением от текущей спецификации (поскольку текущая спецификация настолько недальновидна, что опускает это). Но это настолько смехотворно полезно, что я думаю, что это единственное отклонение было бы оправдано. Подавляющее (VAST) большинство разработчиков TS не будут затронуты незначительными изменениями в реализации, если или когда они наконец будут добавлены в спецификацию ES. Огромные преимущества, которые это может предложить, стоят потенциального будущего воздействия на крошечную часть разработчиков. А учитывая смехотворно медленный процесс спецификации ES, это вообще не имело бы значения в течение нескольких лет (как минимум).

Полностью согласен с brain428

@ brian428 проблема здесь в том, что этот оператор может быть реализован в ES7, поэтому, если машинописный текст будет иметь спецификацию, которая в конечном итоге будет отличаться от окончательной спецификации ES7, никто не будет доволен.

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

Я думаю, что это более позитивный подход для TypeScript — реализовать функции, которые могут _потенциально_ (или не могут) попасть в будущую версию ES, потому что это будет полезный испытательный стенд для влияния на направление ES.

Вот пример обсуждения ES, на который повлиял TypeScript :

Опция TypeScript... для объявления и инициализации через приватный префикс в одном из параметров конструктора была бы полезна многим разработчикам.

Кроме того, ES, безусловно, может принять функцию, которая уже присутствует в TypeScript, но с другой семантикой (например, в отношении того, как работают модули).

ES, безусловно, может принять функцию, которая уже присутствует в TypeScript, но с другой семантикой.

Я должен отметить, что мы в целом считаем, что это наихудший сценарий. Мы очень хотели, чтобы модули в ES6 были завершены до того, как мы объявим TypeScript 1.0, но задержки в расписании комитета помешали этому. Это то, чего следует избегать, а не повторять. Нам бы очень хотелось использовать функции, которые имеют либо ~0% шанс попасть в ES7+ (например, аннотации типов), либо ~100% шанс попасть с легко определяемой семантикой (например, где толстая стрелка была двумя много лет назад). Новые операторы, скорее всего, окажутся в неловкой середине.

В худшем случае, если ES7 действительно отличается, может ли флаг компилятора поддерживать устаревшую реализацию TS, предлагая таким образом льготный период? В сочетании с четкой документацией по миграции это должно предложить разработчикам прямой путь к любому новому стандарту.

В конечном счете, использование любой такой функции, хотя и безумно полезной, не обязательно для разработчиков. TS должен сделать потенциальные будущие последствия его использования предельно ясными с первого дня. Не нравится идея потенциального управляемого рефакторинга, не используйте его. Возможно, флаг компилятора opt-in для принудительного применения этого сообщения?

ТС не должен сходить с ума, желая повлиять на ЭС, но в таких небольших единичных случаях, как этот, было бы обидно, если бы ТС полностью уклонялся.

Может быть, мы могли бы составить предложение для этого, а затем иметь эталонную реализацию с флагом --harmony (или что-то в этом роде). Таким образом, мы сможем стимулировать разработку этой функции в ES7.

Чтобы предотвратить побочные эффекты из-за повторных поисков, компилятору придется либо вывести временные переменные:

($tmp0 = x, $tmp0 === void 0 ? void 0 : 
    ($tmp1=$tmp0.y,  $tmp1 === void 0 ? void 0 : 
        ($tmp2 = $tmp1.z,  $tmp2 === void 0 ? void 0 : $tmp2)))

или используйте мемоизирующую мембрану на основе Proxy .

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

Вопрос о кодеплексе получил довольно много голосов (61).

Мне очень нужно это, чтобы облегчить боль от использования atom для atom-typescript .

Это очень идиоматично в коде coffescript (хотя я бы хотел, чтобы он не был так популярен, поскольку детерминизм лучше, чем вычурный ? ). Откройте любой файл ? , особенно тот, который работает с DOM напрямую, как space-pen (где функции могут выполняться после уничтожения представления или до того, как представление будет прикреплено), и вы обнаружите несметное количество вариантов использования. например, в этом файле есть 16 https://github.com/atom-community/autocomplete-plus/blob/f17659ad4fecbd69855dfaf00c11856572ad26e7/lib/suggestion-list-element.coffee

Опять же, мне не нравится, что мне это нужно, но это состояние JavaScript, и я бы предпочел ? , чем миллион if( && fest ) { then }

Но мне действительно очень нужно, чтобы мой код был читабельным. Это также очень часто _need_ this, когда вы ждете завершения XHR, а angular запускает свой цикл дайджеста.

Хорошо, теперь я прочитал ветку и понял, почему мы ждем. Я понимаю _вздох_.

we'd have to somehow make x, y, z, and foo each evaluate at most once.

coffeescript делает некоторые оптимизации, например , сохраняет промежуточные результаты доступа :

typeof foo !== "undefined" && foo !== null ? (ref = foo.bar) != null ? ref.baz() : void 0 : void 0;

(Я твердо считаю, что проверка undefined не нужна для машинописного текста: так как мы должны иметь проверку типа инициализации var с помощью машинописного текста)

+1

В сегодняшних новостях Dart получает официальную поддержку: https://github.com/gbracha/nullAwareOperators/blob/master/proposal.md

Очень важная особенность.

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

if (aaa?.bbb?.ccc) {}

Может скомпилировать в

if (__chain(aaa, "bbb", "ccc")) {}

Функция __chain должна быть сгенерирована аналогично __extends . Функция __chain может просто выполнить итерацию по массиву arguments , возвращая null , если предстоящий элемент не равен instanceof Object или не содержит имени элемента. Вызовы функций можно было бы обрабатывать, передавая массив в качестве параметра (и используя .apply() под прикрытием), поэтому...

if (aaa?.bbb?.ccc?(1, 2, 3)) {}

Может скомпилировать в

if (__chain(aaa, "bbb", "ccc", [1, 2, 3])) {}

Это также сделает сгенерированный JS достаточно идиоматичным даже для длинных цепочек.

Нуждается явно в доработке... но может тут что-то есть?

Если aaa?.bbb?.ccc? возвращает значение a.b.c , если все реквизиты существуют и это функция, то не может

if (aaa?.bbb?.ccc?(1, 2, 3)) {}

скомпилировать в

if (__chain(aaa, "bbb", "ccc")(1, 2, 3)) {}

?

@metaweta : ваше решение проверяет только void 0 ... разве это не противоречит цели этой функции?

Что насчет этого:

var result = one?.two?.three;

Генерирует:

var $a, $b, $c;
var result = $a = one, $b = $a ? $a.two : void 0, $b ? $b.three : void 0;

Я почти уверен, что это обрабатывает все случаи. Вызовы функций, вероятно, потребуют проверки instanceof Function .

(Незначительный недостаток здесь неожиданных локальных переменных, испускаемых... может быть, может быть обернут в IIFE)

@ kevinb7 : Что произойдет, если ccc не будет функцией? С кодом, который вы описали, __chain всегда будет возвращать действительную функцию, иначе будет выдана ошибка TypeError.

@Back-io Когда свойство отсутствует, поиск возвращает undefined === void 0. Ваше решение не работает при поиске свойств ложных значений, таких как пустая строка и ноль.

@metaweta : нет: http://jsfiddle.net/25LppbL6/

Кроме того, я полагаю, что команда TS не без ума от использования свободного равенства из-за того, что линтеры некоторых людей предостерегают от этого.

@ Back-io Да, это так: http://jsfiddle.net/25LppbL6/2/

@ Back-io Что касается null, я не уверен, какова предполагаемая семантика a?.b. Если это «Если свойство b определено, используйте его», то мой код почти правильный. Единственный способ получить значение null — это если ему присвоить значение null, потому что поиски несуществующих свойств возвращают значение undefined. Он не может уловить случай, когда свойство существует, но имеет значение undefined. Чтобы быть полностью правильным, он будет проверять с помощью Object.hasOwnProperty() вместо сравнения с void 0 === undefined.

Если семантика такова: «если свойство b верно, то используйте его», ваш код в порядке и в некоторой степени соответствует идиоме JS.

Хм ... если я что-то не упустил ... изменения, которые вы внесли в скрипку, еще раз доказывают мою правоту ... var result по-прежнему undefined во всех трех случаях. И я не уверен, какой случай вы пытаетесь выдвинуть, расширяя примитивные прототипы...

Я совершенно уверен, что поведение этой функции будет заключаться в коротком замыкании с void 0 вместо того, чтобы генерировать ошибку. (Мне нравится ваша идея выше, что она всегда должна возвращать void 0 в случае отсутствующего члена).

Каков предполагаемый результат ''?.toString ?

@ kevinb7 : Что произойдет, если ccc не будет функцией? С кодом, который вы описали, __chain всегда должен возвращать действительную функцию, иначе будет выдана ошибка TypeError.

Хорошая точка зрения.

@metaweta : я полагаю, что большинство людей ожидали бы ссылки на функцию toString , поэтому я понимаю, в чем ваша точка зрения. Она несколько ломается в случае, когда вы обращаетесь к членам прототипа 0, false, или ''.

:+1:
Angular 2 добавил оператора Элвиса в синтаксис своего шаблона

@метавета :

Каков предполагаемый результат ''?.toString?

Если бы вы имели в виду ''?.toString() , это было бы:

if ('' != null) {
  ''.toString();
}

Образец

Может быть, мы могли бы составить соломенное предложение для этого

@ kevinb7 он уже существует: http://wiki.ecmascript.org/doku.php?id=strawman:existential_operator

Я сделал несколько быстрых тестов, чтобы реализовать это поверх PropertyAccessExpression в качестве специального случая, но они не сработали, поскольку нам действительно нужно, чтобы ?. был правоассоциативным (вместо левоассоциативного, как . ), иначе эмиттер становится излишне сложным.

Здесь есть комментарий BrendenEich, который также отражает это.

Я сделал несколько быстрых тестов, чтобы реализовать это поверх PropertyAccessExpression в качестве его особого случая, но это не сработало, поскольку нам действительно нужно ?. быть правоассоциативным (а не левоассоциативным, как .), иначе эмиттер становится излишне сложным.

@basarat , не могли бы вы рассказать об этом подробнее? Пример разницы между правоассоциативным и левоассоциативным ?. был бы мне очень полезен.

@zlumer

Пример разницы между правоассоциативным и левоассоциативным ?. был бы очень полезен для меня.

. остается ассоциативным, поэтому выражение foo?.bar?.baz становится в AST (если мы относимся к ?. одинаково):

                    // foo.bar.baz = PropertyAccessExpression
                    //   .expr foo.bar =  PropertyAccessExpression
                    //     .expr foo = Identifier
                    //     .name bar = Identifier
                    //   .name baz = Identifier

Требуется испускание JavaScript

foo != null ? (ref_1 = foo.bar) != null ? ref_1.baz() : void 0 : void 0;

Просто сделать этот выброс (особенно _рекурсивно_) проще, если бы у нас было следующее в AST:

                    // foo.bar.baz = PropertySafeAccessExpression
                    //   .name foo =  Identifier
                    //   .expr bar.baz = PropertySafeAccessExpression
                    //      .expr bar = Identifier
                    //      .name baz = Identifier

Просто подумайте о том, как бы вы преобразовали первый AST в JavaScript, и сложности станут яснее. Надеюсь поможет :rose:

@zlumer , чтобы добавить к тому, что сказал @basarat , я просто приведу пример 1 + 2 + 3 .

При синтаксическом анализе мы должны решить, какая из этих операций произойдет первой.

Если + является ассоциативным слева, это будет интерпретироваться как ((1 + 2) + 3) .

Если + является правоассоциативным, это будет интерпретироваться как (1 + (2 + 3)) .

Вы можете задаться вопросом, действительно ли это будет иметь значение. В JavaScript это было бы! Рассмотрим пример "hello" + 2 + 3 .

  • Лево-ассоциативный: (("hello" + 2) + 3) => ("hello2" + 3) => "hello23"
  • Правоассоциативный: ("hello" + (2 + 3)) => ("hello" + 5) => "hello5"

(Для справки, JavaScript/TypeScript использует левую ассоциативность для оператора + .)

@basarat , мое понимание того, что сказал @BrendanEich (и он может поправить меня, если я ошибаюсь - извините за пинг!) _не_ состоит в том, что ?. является правоассоциативным, а в том, что свойство особых случаев CoffeeScript обращается к право ?. быть правоассоциативным. Например, он будет разбирать

o.p?.q.r.s

так как

((o . p) ?. (q . (r . s))) # or something close to this

вместо

((((o . p) ?. q) . r) . s)

потому что легче излучать.

Наш AST должен хорошо поддаваться здравому семантическому анализу, поэтому наша процедура генерации может позволить себе быть немного более сложной, чтобы удовлетворить эту потребность.

@basarat @DanielRosenwasser спасибо за разъяснения. Пока я понимаю это, но я все еще не уверен в одном.
Левоассоциативный ?. довольно очевиден и ожидаем:

foo?.bar?.baz

Становится (прибл.):

var ref = ((ref = foo) == null) ? null : ((ref = ref.bar) == null) ? null : ref.baz;

Но я вообще не понимаю, как будет работать правоассоциативный ?. . Не могли бы вы привести пример?

Но я вообще не понимаю, как бы правильно-ассоциативный?. работай. Не могли бы вы привести пример

@zlumer Поведение во время выполнения останется ассоциативным. Я только что говорил о AST, как пояснил Даниэль Розенвассер: is not that ?. is right-associative, but that CoffeeScript special cases property accesses on the right of the ?. to be right-associative .

Наш AST должен хорошо поддаваться здравому семантическому анализу, поэтому наша процедура генерации может позволить себе быть немного более сложной, чтобы удовлетворить эту потребность.

@DanielRosenwasser спасибо за отзыв :rose:

@basarat спасибо, вдруг все стало ясно :smiley:

Как и в февральском комментарии @basarat , я.... _sigh_...

Однако, если подумать, 99% вариантов использования этого будут заключаться в проверке нулевого указателя на объект. Откровенно говоря, кто делает x?.b?.c , когда x — это number ? Просто не так много реальных случаев использования _длинных_ цепочек, когда мы _не_ говорим об объекте (за возможным исключением string ). Для коротких цепочек, я думаю, мы можем жить с x && x.b или x === 0 ? null : x.b .

Итак, можем ли мы сказать, что ?. работает только с объектными типами? Любой другой тип вызывает синтаксическую ошибку. И запретить вызовы функций внутри цепочки.

Затем все это транскрибируется в a && a.b && a.b.c .

@schungx Что, если член цепочки относится к типу «любой»? Полностью запретить? Или просто терпеть и надеяться на лучшее?

Ну, мое предложение? Полностью запретить. Неэлегантно, черт возьми, я знаю... :-)

Но мое обоснование:

  1. Это сокращенная запись, поэтому, если кто-то использует any , просто используйте полную запись.
  2. Если кто-то использует TypeScript, скорее всего, он/она использует его для поддержки набора текста, так что, надеюсь, у него/нее не будет много any !
  3. С any действительно следует обращаться осторожно. Разрешение использования таких сокращений с гибким типом, таким как any , действительно требует появления ошибок. На мой взгляд, any должно быть как можно меньше. Это похоже на C (void *) — тот факт, что вам вручили ядерное оружие, не означает, что вы должны активировать его только потому, что можете!

Это был бы потрясающий оператор!! Специально для ES6 / ES7 / TypeScript

var error = a.b.c.d; //this would fail with error if a, b or c are null or undefined.
var current = a && a.b && a.b.c && a.b.c.d; // the current messy way to handle this
var currentBrackets = a && a['b'] && a['b']['c'] && a['b']['c']['d']; //the current messy way to handle this
var typeScript = a?.b?.c?.d; // The typescript way of handling the above mess with no errors
var typeScriptBrackets = a?['b']?['c']?['d']; //The typescript of handling the above mess with no errors

Однако предлагаю более ясный вопрос - как не перепутать? из а? b : операторы c с операторами a?.b:

var doubleDots = a..b..c..d; //this would be ideal to understand that you assume that if any of a, b, c is null or undefined the result will be null or undefined.
var doubleDotsWithBrackets = a..['b']..['c']..['d'];

Для обозначения в скобках я рекомендую две точки вместо одной, поскольку они согласуются с другими, когда не используются скобки. Следовательно, только имя свойства является статическим или динамическим через скобки.

Две точки означают, что если его нуль или неопределенность прекращают дальнейшую обработку и предполагают, что результат выражения равен нулю или не определен. (поскольку d будет нулевым или неопределенным).

Две точки делают его более четким, более заметным и более объемным, чтобы вы понимали, что происходит.

Это тоже не возится с цифрами - это не тот же случай, например

1..toString(); // works returning '1'
var x = {};
x.1 = {y: 'test' }; //fails currently
x[1] = {y: 'test' }; //works currently 
var current = x[1].y; //works
var missing= x[2].y; //throws exception
var assume= x && x[2] && x[2].y; // works but very messy

Насчет номеров два варианта: Ваш звонок какой можно принять, но я рекомендую первый для совместимости с существующими правилами!

  1. Должен потерпеть неудачу, как сейчас ( x.1.y == runtime error )
var err = x..1..y; // should fail as well, since 1 is not a good property name, nor a number to call a method, since it's after x object.
  1. Должно работать, так как он понимает, что это не номер, вызывающий свойство из Number.prototype
var err = x..1..y; // should work as well, resulting 'test' in this case
var err = x..2..y; // should work as well, resulting undefined in this case

С динамическими именами:

var correct1 = x..[1]..y; //would work returning 'test'
var correct2 = x..[2]..y; //would work returning undefined;

Как вы думаете, ребята?

PS Синтаксис foo?.bar и foo?['bar'] тоже подойдет.

Однако использование текущего оператора ? : и оператора ?. может привести к путанице в одной строке.

например, используя ?. и ?['prop']

var a = { x: { y: 1 } };
var b = condition ? a?.x.?y : a?.y?.z;
var c = condition ? a?['x']?['y'] : a?['y']?['z'];

в отличие от двойных точек .. и ..['prop']

var a = { x: { y: 1 } };
var b = condition ? a..x..y : a..y..z;
var c = condition ? a..['x']..['y'] : a..['y']..['z'];
Какой из них кажется вам более понятным?

Очень интересно. :+1:

ИМХО, с двумя точками будет больше путаницы. Существуют языки, в которых две точки обозначают диапазон (например, 1..4 ), и TypeScript может добавить эту функцию в будущем.

Знак вопроса также имеет семантическое значение неопределенности или условности, а две точки не передают одно и то же значение.

@schungx Достаточно справедливо, но это помогло бы для таких странных возможностей, как эта: a?['b'] или эта a?() .

+1 ?

a?['b'] и a?() прекрасно себя ведут в coffeescript, и мне они нравятся.

Но опять же, я могу быть просто слепым к кофе.

+1 Ruby только что реализовал экзистенциальный оператор https://twitter.com/mikepack_/status/657229703443451904. Typescript тоже нуждается в этом, независимо от конкретного синтаксиса.

Это сделало бы код чище 👍

+1 Это нужно!

Пожалуйста, импленент?. оператор, как это делает C#

+1 давно этого не хватало

+1
так некрасиво писать: someVariable && someVariable.someMember
когда можно было написать: someVariable?.someMember

+1, это было бы здорово.... (самая нужная функция для меня)

+1, это хорошая идея!
Только, если объект сложный, выражение будет заполнено знаком ?. после каждого свойства (var result=myValue?.a?.b?.c?.d?.e;), когда мне нужно получить значение последнего (var result=?myValue.abcde;).

+1 - Это, возможно, одна из величайших функций CoffeeScript и, безусловно, самая желанная функция TypeScript для моей команды после преобразования большей части нашего кода из CS в TS.

+1 однако это слишком сложно:

var x = { y: { z: null, q: undefined } };
var z: x|y|z = x?.y?.z;

Мне это нравится:

var x = { y: { z: null, q: undefined } };
var z: z|void = x?.y?.z;

Тип x?.y?.z всегда совпадает с типом поля z . Конечно, тип должен быть обнуляемым, и фактическое значение может быть нулевым. Если оно не равно нулю, то оно должно иметь тип поля z .

+1 Это хорошо сочетается с видением Typescript по упрощению разработки крупномасштабных сложных JS-проектов.

Есть новости по этому поводу? Это тот случай, когда сообщество голосует за эту функцию? Или это рассматривалось, но есть какие-то инженерные проблемы?

Пока никаких обновлений, потому что введение нового синтаксиса на уровне выражений опасно без какого-либо предложения от комитета ECMAScript.

См. https://github.com/Microsoft/TypeScript/issues/16#issuecomment-57645069 .

Вот более актуальное обсуждение экзистенциальных операторов (много мыслей, но мало действий):

где я должен написать "+1", чтобы помочь привести его в ES?

Закрытие на данный момент. Поскольку на самом деле нет ничего специфичного для TypeScript, которое потребовало бы этого на уровне выражения, такое большое изменение оператора должно произойти в комитете спецификации ES, а не здесь.

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

жизнь - отстой

Удаление автономного :+1:s. Пожалуйста, используйте функцию реакции GitHub или отправьте цветы и конфеты ближайшему представителю TC39.

Как только я привык к этому в coffeescript и Swift, пути назад уже не будет. TS мертв для меня в его нынешнем виде.

@algesten Я могу согласиться с swift , если мы рассмотрим сам язык, но не уверен в долгосрочной поддержке coffescript (я использую CoffeScript в производственных проектах). Мы можем согласиться быть уверенными в тенденциях языковой аналитики по состоянию на июнь 2016 года, когда мы можем ясно видеть, что происходит с coffescript последнее время, в то время как TypeScript демонстрирует самый быстрый рост за последние годы:

TypeScript: за исключением Go или Swift, самым быстрорастущим языком, который мы наблюдали в последние годы, является TypeScript. Поддерживаемый Microsoft расширенный набор JavaScript и основа Angular 2 добились значительных успехов второй квартал подряд, поднявшись с 31-го на 26-е место. Это было самое большое изменение среди языков, входящих в топ-30, и второе по величине скачок в целом (Standard ML, 7 позиций). Фактически, на 26-м месте TypeScript теперь связан с Erlang, отставая от Powershell на одно место и отставая на четыре от CoffeeScript, который находится сразу за пределами топ-20. Вопрос, стоящий перед языком, заключается не в том, сможет ли он расти, а в том, есть ли у него импульс. чтобы пробиться в топ-20 в течение следующих двух-трех кварталов, обогнав в процессе таких, как CoffeeScript и Lua.

До 2014 года coffescript был более чем положительным, как вы можете посмотреть здесь , именно тогда и начался спад.

С новым typescript 2.0 строгая проверка null (undefined) является обязательной, потому что иначе вы не можете использовать цепочку функций!

Это должно быть в следующей версии ECMAScript. Учитывая, что это было бы еще более полезно в ванильном JavaScript, чем в TypeScript, и учитывая, что реализация, естественно, будет проверкой на undefined или null, а не на правдивую проверку, добавление TC39 должно быть тривиальным.

Простая реализация, которая была бы идиоматична в JavaScript, заключалась бы в коротком замыкании при встрече с нулевым или неопределенным значением и возвратом неопределенного значения.

@bterlson это имеет смысл? Каковы шансы, что такое предложение будет принято?

Одним из больших преимуществ машинописного текста является то, что «будущее дано вам сегодня». Это одна из особенностей, которой я был удивлен, что ее еще нет.

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

Замечательная проверка нулей в TS 2 превратила его в нечто необходимое!

Читая эту ветку, я немного удивлен, как это не привлекает больше внимания со стороны сопровождающих.

В идеальном мире TypeScript должен идти впереди ES, а не наоборот. Серьезно, где сейчас был бы TypeScript, если бы команда TS всегда ждала, пока ESx предложит и доработает функцию или синтаксис?

Этот синтаксис действительно «должен быть», как указывали другие. Он даже получил несколько хороших предложений в этой теме до сих пор. Я думаю, что реализация должна соответствовать этим ожиданиям.

  • В общем случае выражение a?.b должно быть допустимо во время компиляции тогда и только тогда, когда допустимо выражение $# a.b .
  • Он должен оценивать каждое выражение в цепочке только один раз.
  • Должно быть короткое замыкание.
  • Если выполнение достигает середины выражения со значением null или undefined , то это значение должно быть возвращаемым значением.

Как вы думаете, какие части могут привести к разногласиям, когда ES уточнит это?

Для a?.b я не вижу конфликтов с существующим (и будущим?) синтаксисом. Если синтаксический анализатор находит токен ?. , он может рассматривать его как «оператор безопасной навигации» (с ожиданиями, описанными @cervengoc).

Синтаксические конфликты возникают только при разрешении a?(b) и a?[b] , поскольку они также могут быть интерпретированы как начало троичного операторного выражения ?: . Но для начала я думаю, что их можно было бы отложить в сторону, и поддержка только синтаксиса a?.b уже сделала бы многих разработчиков счастливыми!

В идеальном мире TypeScript должен идти впереди ES, а не наоборот.

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

Этот синтаксис действительно «должен быть», как указывали другие.

Если это необходимо для TypeScript, это необходимо и для JavaScript! Опять же, сообщите о своих опасениях комитету ECMAScript .

Как вы думаете, какие части могут привести к разногласиям, когда ES уточнит это?

Как минимум, я думаю, будут разногласия по поводу того, замыкается ли синтаксис на null или undefined при встрече с этими значениями или всегда замыкается на undefined . Также будут разногласия по поводу того, поддерживается ли какая-либо форма синтаксиса в квадратных скобках. Также возникает вопрос, как ведет себя a?.b.c . Есть также вопрос о ?. против .? против a.b? . Возникает вопрос, как это повлияет на оператор delete .

Тема ES DIScuss по этому вопросу насчитывает более 100 комментариев. Нет недостатка в двусмысленности! Легко посмотреть на один изолированный пример и подумать, что не может быть тонны крайних случаев. Есть. Вероятно, поэтому никто еще не отстаивал это на TC39, и _также_ почему мы не торопимся добавлять функцию, в отношении того, как она должна себя вести, много неясностей.

Прошу прощения, я не читал упомянутую ветку, я обязательно посмотрю, чтобы увидеть больше.

Мы видим это немного по-другому. Что касается комитета, по моему честному мнению, это одна из главных причин, почему JavaScript никогда не будет _хорошим_. Просто для примера, многие из самых успешных программ, которые я видел (например, Total Commander или IrfanView), успешны, потому что они поддерживаются и разрабатываются ОДНИМ человеком, а не *комитетом». правильный пример Но я почти уверен, что если бы, например, вы один разработали полный ES6, то мир сейчас был бы лучше.

Кроме того, двусмысленности, о которых вы упомянули, на 99% являются _теоретическими_ вещами и не имеют значения со стороны разработчика. Кому какое дело до того, что он возвращает, null или undefined ? Просто выберите один, и мы будем использовать его таким образом.

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

Конечно, без обид, не принимайте ничего на свой счет, я очень уважаю вас и всю команду TS, потому что вы произвели революцию в разработке клиентской части для многих разработчиков, включая меня, и спасибо вам за всю вашу работу. Мы просто немного разочарованы этим конкретным, я думаю.

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

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

В общем, вы и этот комитет находитесь на другой стороне, чем большинство из нас, и вещи с этой стороны обычно более сложны, чем они есть на самом деле.

Я не думаю, что вы точно отражаете истинный статус Райана или TC39. Райан и команда TypeScript поставили перед собой очень четкие цели проектирования TypeScript. Одна из первоначальных и до сих пор очень актуальных целей заключается в том, что TypeScript является надмножеством JavaScript. Не тот язык, который люди хотели бы видеть (например, Dart, Haxe). Когда дело доходит до синтаксиса, команда TypeScript на собственном горьком опыте усвоила стоимость его предварительного изобретения (например, модулей). Мы также движемся к проблеме с частными членами классов, где предлагаемый синтаксис ES полностью несовместим с синтаксисом, используемым TypeScript. Почему? Потому что то, что может показаться несложным на первый взгляд, невозможно реализовать, учитывая сложности языка во время выполнения.

На мой взгляд, TC39 «спас» JavaScript. От ES4 отказались не потому, что ему не хватало хороших, инновационных идей, а потому, что он взорвал бы Интернет. TC39 привели себя в форму, они поделились и были полностью открыты в своих дискуссиях и о том, как они принимают решения, и представили нам ES2015, который во многом похож на ES4, но не сломал Интернет. Удивительно, что у нас есть среды выполнения JavaScript, которые прекрасно запускают код 10-летней давности, но поддерживают множество значительных улучшений языка. ES2016 был затишьем перед бурей. ES2017 имеет «разумное» количество функций и изменений, а также четкий процесс управления, который движется в правильном направлении.

Так что, на мой взгляд, пребывание на «другой стороне» вещей явно сработало. Что превосходит целесообразность «обязательных» функций.

@kitsonk Я не имел в виду «другую сторону» отрицательно, и особенно я не хотел ухудшить работу, которая была помещена в TypeScript или ES6. Более того, лучшая вещь в TypeScript IMO — это то, что у него действительно была и есть четкая цель дизайна, и он хорошо защищен от хаоса, как и многие другие вещи с открытым исходным кодом.

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

Я понимаю, что с вашей стороны неприятно то, что, например, частные участники стали несовместимы с окончательной концепцией ES6. Но, с другой стороны, у нас это было. Задолго до ES6. И это главное с нашей стороны. Грубо говоря, нас не волнует, как вам удастся сгенерировать соответствующий код для него, мы просто с удовольствием его используем. То же самое с модулями и всем остальным. Мы (или, по крайней мере, я) не видели тех проблем, о которых вы говорите, мы всегда были довольны приватными членами или модулями.

Эта конкретная функция есть в CoffeScript, как я читал об этом. Почему нам, простым разработчикам, всегда приходится идти на компромиссы при выборе платформы/библиотеки/плагина и т.д.? Я имею в виду всегда . Это немного раздражает. Здесь у нас есть отличный язык с большим потенциалом, который полностью оставляет позади всех остальных участников (включая ES!), и который успешно произвел революцию в огромной части клиентской разработки, и когда дело доходит до этой «простой» функции ( Я имею в виду, по крайней мере, часть доступа к членам), мы слышали, что она не будет реализована, пока ES не сделает этого.

Я хотел быстро сообщить людям, что эта функция переместилась с этапа 0 на этап 1 на сегодняшнем собрании TC39.

Соответствующий коммит: https://github.com/tc39/proposals/commit/cb447642290a55398d483f5b55fb7f973273c75d
Программа встречи: https://github.com/tc39/agendas/blob/master/2017/01.md

Ух ты! это огромное!

Также стоит ссылка на https://github.com/claudepache/es-Optional-Chaing

Некоторые «сюрпризы», которые я вижу здесь (не говорю, что я не согласен, просто то, что мы, вероятно, сделали бы по-другому, если бы сделали это раньше):

  • null не получается из выражения a?.b : когда a равно null #$, вместо этого получается undefined
  • ~ Распространение в цепочках точек: a?.b.c.d не будет генерироваться, если свойства b и c равны undefined ~ Райан не умеет читать
  • ~ Распространение при наличии скобок : даже (a?.b).c не будет выброшено, если b не определено~ Райан не может читать
  • ~ Распространение происходит даже при вызовах методов: a?.b.c().d вернет undefined , если вызов c вернет null ~ Райан не может читать
  • Поддерживается оператор delete
  • Поддерживается синтаксис брекетинга a?.[x]
  • Синтаксис вызова функции func?.(...args) поддерживается даже для вызовов без методов (!)

Я ожидаю увидеть изменения в этих областях между настоящим моментом и этапом 2.

Я думаю, что coffeescript понял это правильно.

a?.bc выбрасывает, если b не определено.

a?() и a?[0] хороши.

  • Распространение в цепочках точек: a?.bcd не будет генерировать, если свойства b и c не определены
  • Распространение при наличии скобок: даже (a?.b).c не будет выброшено, если b не определено
  • Распространение происходит даже при вызовах методов: a?.bc().d вернет undefined, если вызов c вернет null

Эти пункты не кажутся мне точными. Из предложения:

a?.b.c().d      // undefined if a is null/undefined, a.b.c().d otherwise.
                // NB: If a is not null/undefined, and a.b is nevertheless undefined,
                //     short-circuiting does *not* apply

Вау, я совершенно неправильно это понял. Ты прав. Обновление

@algesten из исходного предложения:

a?.()

b?.[0]

милая. тогда оператор может выглядеть как ?. .

Здесь происходит дополнительный разговор: https://github.com/estree/estree/issues/146 .

Цитата, которая может подойти: «Сделайте простые вещи легкими , а сложные — возможными ». Таким образом, возможно, хорошо поддерживать наиболее распространенные случаи, пропуская (по крайней мере, на начальном этапе) сложные/редкие случаи, в то время как их все еще можно "выполнять вручную" с более длинным (существующим) синтаксисом.

Просто мои два цента

let a = b?.c?.d?.e;

к:

let a;
try{
   a = b.c.d.e;
}catch(e){
   a = undefined;
}

@cedvdb совершенно другая семантика - исключения, созданные в геттерах, не должны вызывать объединение

@RyanCavanaugh да .. Я не подумал об этом.

Находится ли это на радаре для реализации сейчас, или команда TS будет ждать, пока предложение ES продвинется дальше?

Это в нашем коротком списке; у нас все еще есть несколько вопросов/проблем, но вы должны увидеть движение по этому вопросу в следующем месяце.

Не уверен, откуда взялся комментарий @mhegazy - количество открытых вопросов по предложению TC39 слишком велико, чтобы мы могли здесь провести содержательную работу. В частности, сначала необходимо решить вопросы о том, как взаимодействуют null и undefined и какой синтаксис на самом деле поддерживается. Этап 2 — это абсолютный минимум, и мы бы предпочли этап 3, учитывая его влияние на поведение во время выполнения.

это просто код работает?

a == undefined ? expression : undefined

expression означает, что здесь также могут быть сгенерированы ax, a[x], a(x), delete

тогда a?.b?.[c]?.(d) сгенерирует

a == undefined ? (a.b == undefined ? (a.b[c] == undefined ? a.b[c](d) : undefined) : undefined) : undefined

кажется пройдет через все правило Райана Кавано


если оператор ненависти == , это также может быть a === undefined || a === null

@ zh99998 вы _должны_ ненавидеть == , потому что '' и 0 также приравниваются. Почти утверждается, что поведение во время выполнения должно быть своего рода проверкой (typeof value === 'object' || typeof value === 'function' || typeof value === 'symbol') && value !== null , что сейчас становится довольно сложным.

Как сказал @RyanCavanaugh , это вряд ли будет прогрессировать, пока предложение TC39 для него не перейдет как минимум на этап 2 или 3.

Я вижу, что == равно только null и undefined как
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness

и тест прошел в хромированной консоли:

'' == undefined
false
0 == undefined
false

@kitsonk undefined только принуждает к нулю и наоборот. Никакое другое значение не приводит к неопределенному или нулевому значению.

Вы, кажется, запутались с ложными значениями. 0 и "" действительно ложны, но никогда не приведут к нулю или неопределенности.

== подразумевает принуждение. null == 0 является ложным, потому что ничто, кроме undefined, не может привести к нулевому значению. То же самое касается undefined == 0 .

Другой пример может быть

    if(!NaN) console.log("NaN is falsy") // NaN is falsy
    if(false == NaN) console.log("NaN coerces to false")
   else console.log("NaN doesn't coerce to false");// NaN doesn't coerce

Вы получаете картину.

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

К счастью, в JavaScript есть IIFE, поэтому вы можете хранить результат доступа в параметре функции, ссылаться на него столько раз, сколько хотите, и никогда не оценивать его более одного раза. В приведенном ниже примере я создаю лямбду coalesce , которую можно вызывать несколько раз вместо выражения, содержащего операторы ?. .

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

const coalesce = (x: any, y: string) => x == null ? null : x[y];

const x = {
    y: {
        z: "Hello, World!!!"
    },
    f: () => "Foo!",
    a: ["Array!"]
};

// x?.y?.z
const value1 = coalesce(coalesce(x, 'y'), 'z');

// x?.f()
const value2 = coalesce(x, 'f')()

// x?.a[0]
const value3 = coalesce(x, 'a')[0]

Обратите внимание, что нет необходимости в фактическом глобальном имени «coalesce». Этот код может быть непосредственно встроен в любое выражение. Тем не менее, это может сократить раздувание, дав ему имя.

Меня не слишком беспокоит синтаксис, используемый для оператора, или хотят ли разработчики языка ждать стандарта. Просто подумал, что я покажу другой подход.

Это также вызывает потребность в операторе ?? . В C# это заменяет любое выражение null тем, что находится справа.

string x = null ?? "Hello";
````

In JavaScript, it is more idiomatic to use `||` to replace "falsey" values with the value on the right. 

```javascript
var x = null || "Hello";

К сожалению, правдивость охватывает слишком много пограничных случаев ( 0 , false и т. д.). Работая с нулевым оператором объединения ( ?. ), вам нужно что-то конкретное для null -ness.

const x = { y: "" };
const result1 = x?.y || "default";  // I'd expect "default"
const result2 = x?.y ?? "default";  // I'd expect "" 

@jehugaleahsa , в вашем примере с объединением должен быть способ предотвратить вызовы функций и доступ к членам, если проверка перед возвратом значения null. В примере x?.f() функция f не должна вызываться, если x имеет значение null.

@bschlenk Я не думаю, что согласен. Я думаю, что это должно завершиться ошибкой с сообщением вроде null is not a function , но, думаю, это не зависит от меня.

Недавний всплеск комментариев с подробным описанием возможных способов реализации оператора выглядит немного странно.
Реализация, вероятно, является решенной проблемой.

Если вам интересно, есть библиотека idx , которая очень напоминает поведение оператора ?. , хотя и игнорирует многие детали запланированного оператора. В любом случае, их спецификации для вывода компиляции могут представлять интерес для всех, кто интересуется способами реализации этого материала.

TS может выводить что-то подобное, а может выводить что-то совершенно другое, но я не думаю, что это то, чего мы здесь ждем. Здесь много раз говорилось, что TS не получит оператора, пока предложение ES не сдвинется в ту или иную сторону.

Это семантика, в которой все еще есть некоторые неизвестные, перечисленные здесь и здесь .

Будьте уверены, что мы реализуем это правильно, и нам не понадобится еще 100 комментариев, чтобы понять, что делают || и ? ... : ... . Как отметил @noppa , мы просто ждем завершения спецификации ES.

https://github.com/babel/babel/pull/5813 (сопровождающий пиар Babylon ) был просто слит с Babel’s preset-stage-1 . Конечно, спецификация все еще находится на стадии 1, но это поможет продвинуть ее вперед.

Возможно, я ошибаюсь, но я не видел явной ссылки на предложение tc39 в этой ветке, так что вот она для будущих читателей: https://github.com/tc39/proposal-Optional-Chaing

Необязательная цепочка FYI будет на TC39 на следующей неделе https://github.com/tc39/agendas/blob/master/2017/07.md

@jehugaleahsa Думаю, вы правы, и на следующей неделе я представлю ?? на TC39. Вы можете следить за предложением здесь: https://github.com/gisenberg/proposal-nullary-coalescing

Я вижу, что на TC39 рассматривалась опциональная цепочка... Каков был вердикт?
Надеюсь, этого было достаточно, чтобы продвинуть это вперед в Typescript 😉

@markwhitfeld Из сводки заметок :
Необязательные операторы цепочки: остаются на этапе 1, вернутся позже с более четкими определениями различных параметров и ответами на отзывы.

Полные примечания здесь: https://github.com/rwaldron/tc39-notes/blob/master/es8/2017-07/jul-27.md#13iia -Optional-chaining-operator

Остаются открытыми вопросы о том, как должен вести себя оператор, поэтому похоже, что он еще не в том состоянии, когда его можно добавить в TypeScript.

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

Я очень надеюсь, что они выберут вариант 2/4 (который в любом случае является текущим состоянием предложения).

15 июля 2014 г. - 4 сентября 2017 г., еще ничего

@frankfvb вы явно не читали выпуск.

Было много дискуссий, которые привели основную группу к выводу, что было бы неблагоразумно реализовывать на данном этапе, пока не будет достигнут дальнейший прогресс в предложении ECMAScript , которое напрямую повлияет на функциональность этой функции в TypeScript.

По состоянию на последнее собрание комитета по стандартам ECMAScript предложение остается на этапе 1 , поскольку у него есть несколько очень фундаментальных вопросов о том, как оно будет реализовано. Хотя это и не является жестким и быстрым правилом, TypeScript будет реализовывать только предложения этапа 3. Иногда он реализует предложения этапа 2, если они считают, что это имеет решающее значение, и потенциальное использование в TypeScript стимулирует эволюцию стандарта.

Я не уверен, как другие более ясные люди могут быть об этом.

Как я уже говорил ранее , это в нашем коротком списке. мы ждем от TC39 достижения какого-то консенсуса по семантике оператора. мы бы не хотели выпускать его, а затем ломать пользователей.

Это не та ветка, чтобы перефразировать обсуждение TC39.

Если вы хотите оценить предложение, прокомментируйте его в соответствующем месте . У меня тоже есть мнения, но их обсуждение в этой теме ничего не даст.

Я создал что-то простое, что отвечает моим текущим потребностям. Он будет работать только в цепочке, где каждая ссылка является именем свойства, поэтому доступ к элементу в массиве (например) не поддерживается.

Реализация действительно простого оператора Элвиса в TypeScript

Также, если у вас есть lodash/underscore, вы уже можете использовать _.get(Book, 'author.name.firstName') , который будет делать то, что он хочет.

Редактировать: по-видимому, это плохой совет из-за проблем с типом метода _.get() . Смотрите комментарий ниже

@tolgaek , _.get имеет плохую типизацию, даже с этой лучшей типизацией ( еще не объединенной из-за авторов) машинописный текст может определенно вывести тип результата, только если глубина объекта равна 1, во всех остальных случаях это any и должен быть проверен во время выполнения

С другой стороны, с помощью оператора elvis typescript может определить тип результата в объектах любой глубины, поэтому я с нетерпением жду оператора elvis.

о, я вижу, я не знал, что есть проблема с набором текста. Спасибо @BjornMelgaard

@mhegazy нельзя ли сначала реализовать эту функцию и пометить ее как экспериментальную? Я думаю, что у людей не должно быть проблем, если в экспериментальной функции изменена спецификация.

Элвис не в восторге от ожидания так долго.

Он приземлился в Babel7. Машинопись, мы работаем медленно.. Кто-нибудь, пожалуйста, сделайте это.
:)

@gs-akhan Плагин Babel реализует старую версию предложения, сделанного несколько месяцев назад. С тех пор в предложение были внесены изменения (в том числе значительное изменение в том, как анализируется оператор), и, вероятно, будут внесены дополнительные изменения, прежде чем функция достигнет стадии 2 (не говоря уже о стадии 3), поэтому любой код, написанный с использованием текущей версии Babel плагин может сломаться, когда фактическая функция будет выпущена. Babel намеренно реализует предлагаемые функции до того, как они станут стабильными, чтобы авторы спецификаций и другие заинтересованные стороны могли опробовать предлагаемую функцию. Тот факт, что Babel реализовал функцию, не означает, что ее можно реализовать таким образом, чтобы в будущем не потребовались критические изменения.

@alangpierce Это имеет смысл. Спасибо

Я понимаю, что это очень, очень хороший оператор, но то, что он будет доступен до того, как его правила будут сглажены, — это пушка, и мы не собираемся этого делать. Поведение оператора во время выполнения все еще меняется; если вы напишете код сегодня, он может перестать работать завтра, что не сразу заметно — может быть, редкие сбои, может быть, повреждение данных, кто знает? Немного терпения сейчас избавит вас от боли через несколько месяцев.

Начинаю думать, что этот тикет должен быть заблокирован (не закрыт) до тех пор, пока спецификация не будет готова.

Когда спецификация будет готова?

@oliverjanik Текущий проект спецификации можно найти здесь . В повестке дня есть пункт о продвижении предложения на этап 2 на следующем собрании TC39 (26.09-28.09). Я буду представлять эти слайды в то время. Тех, кто хотел бы предварительно просмотреть и оставить отзыв, просьба сообщать о проблемах в репозитории предложений .

Большое спасибо @gisenberg за то, что отстаиваете эту проблему для нас! Я думал о том, чтобы составить краткий набор слайдов, чтобы помочь прояснить варианты, связанные с оператором, которые можно было бы использовать на собрании TC39, чтобы избежать путаницы, но вы уже сделали это. Потрясающая работа!
Может быть, еще одна вещь, которая может быть полезна для разговора по TC39 (и презентации слайдов), — это рассмотрение семантики и синтаксиса оператора на других языках. Хотя другие языки не обязательно должны диктовать, как он должен работать в Javascript, было бы полезно сохранить оператор, аналогичный оператору в других языках, чтобы избежать путаницы.
Удачи на следующей неделе!!!

Извините, что снова немного отклоняюсь от темы, но я подумал, что некоторым здесь может быть интересно, что в Flow теперь можно добавить несколько рабочих определений типов для безопасных функций-получателей, таких как _.get .

Пример: flowtype.org/try

Не самый красивый фрагмент кода, и он неправильно различает null и undefined, но в остальном он работает довольно хорошо.

Насколько я знаю, единственное, чего не хватает в TS, чтобы сделать то же самое, это что-то вроде этого $NonMaybeType .
Не то, чтобы это убрало необходимость в этом операторе, конечно, я просто подумал, что это круто.

Это не достигло этапа 2 на последнем собрании TC39 из-за опасений по поводу синтаксической согласованности в отношении доступа к скобкам, точкам и вызовам, а также семантического поведения (предсказуемость побочных эффектов выражений справа от undefined / null ). x.?b() , когда x.b является number )

(проголосуйте 🎉 под этим комментарием, чтобы бросить гнилые фрукты)

Спасибо за то, что дали нам знать. Какой облом. Может быть, нужно сузить область, чтобы было проще, но все же полезно?

Может быть, нужно сузить область, чтобы было проще, но все же полезно?

Это вызов, с которым сталкивается TC39, который, хотя и отстойный, должен признать, что я рад, что люди проходят через это. Им действительно сложно ввести довольно сложный синтаксис уровня, и на самом деле, в этом случае слабая типизация языка на самом деле вызывает значительное количество пограничных случаев, которые необходимо решать, или вы получаете код, который работает 💥 который не работает. ни для кого не годится. Я не думаю, что если вы введете такой оператор, вы действительно сможете сузить его область применения. Разработчикам было бы проще охватить 90% случаев, но я не думаю, что код ¯\_(ツ)_/¯ подходит для оставшихся 10%.

Ребята, спустя 3 с лишним года я бы сказал, что пришло время сказать комитету «иди на хуй» и сделать это по-своему, что бы ни было идиоматично для TypeScript. В любом случае, эта функция не может работать должным образом без статической типизации.

Сделайте реализацию TypeScript с синтаксисом, явно несовместимым с предложением TC39. Как только ES получит оператор безопасной навигации, у TypeScript будет два варианта: один с дерьмовой семантикой, совместимой с ES, и другой, привязанный к системе типов. Это означает, что вы не можете использовать оператор TS safe-nav с любым «типом», и это нормально.

@notsnotso Typescript не должен ломать JS, для этого и нужен Coffeescript.

Возможно, хорошее решение:

  • реализовать очень просто? оператор для нетерпеливых разработчиков, как экспериментальная функция (например, декоратор), с предупреждением - это сломает ваш код в будущем
  • подождите еще 3 года, когда напишут стандарт, внедрить как неэкспериментальную фичу. Напишите туториал, что могло сломаться. Даже при статической типизации можно писать предупреждения, когда люди будут компилировать код с новой реализацией оператора.
    «Делайте по-своему, что бы идиоматично для TypeScript» это не тот случай, потому что через 3 года люди столкнутся с проблемой, что ts elvis работает не так, как в js.

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

Я бы предпочел более универсальную утилиту, решающую эту проблему.
и больше. Одна мысль, которая у меня была, была что-то вроде встроенной try/catch
выражение ( let x = try a.b.c else 0 ) в сочетании с оператором, который
проверяется на "null" (например, x ?? 1), а не на "falsy" (например, x || 1).
Итак, вы бы объединили их так: try a.b.c ?? 0 else 0 . Это многословно, да,
но в основном он говорит: попробуйте оценить abc, и если результат null или
undefined , вернуть 0. Если a или b равно undefined и возникает исключение,
поймать его и вернуть 0.

В качестве альтернативы можно было бы сделать предложение else необязательным, по умолчанию
undefined . Тогда вы можете написать выражение как: let x= (try a.b.c) ?? 0 . Это чертовски компактно, позволяет избежать двусмысленности и обеспечивает более
универсальное решение, которое может решить другие проблемы.

Я не говорю, что мы должны настаивать на этом; все, что я говорю, есть
являются альтернативами ?. , и нам действительно следует изучить наши варианты, пока мы не
найдите тот, который хорошо подходит для языка JavaScript.

Чт, 5 октября 2017 г., 7:51, Дмитрий Радковский, notifications @github.com
написал:

@notsnotso Typescript не должен ломать JS, вот что
Кофескрипт для.


Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/Microsoft/TypeScript/issues/16#issuecomment-334441781 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/ABTgPilbZfuKc2egdBrYfdTHHeDl3F6Sks5spMLLgaJpZM4CNapf
.

@zlumer хорошая шутка. Тем не менее, специфическая функция TS не нарушит Javascript.

@jehugaleahsa Мне нравится ваше предложение, и оно есть на других языках. Я думаю, что для ТС вполне подойдет.

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

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

async/await также был представлен в TypeScript на ранней стадии.

Тем не менее, специфическая функция TS не нарушит Javascript.

Не будет чего-то вроде «специальной функции TS», пожалуйста, ознакомьтесь с целями дизайна TypeScript для получения дополнительной информации.

TypeScript появляется до того, как ES пойдет по светлому пути, могут быть некоторые уже существующие,они просто сохранены для совместимости.

TypeScript добавил классы, модули, лямбда-выражения задолго до того, как они попали в ECMAScript.

И модули, в частности, представляют собой огромное фиаско, которое до сих пор не дает конца путанице. Это пример, который команда TypeScript неоднократно использовала в качестве примера _ошибки_ и слишком ранней спешки. Теперь у нас также вырисовываются частные поля, которые, опять же, я был благодарен за private за последние 5 лет, но это вызовет бесконечную путаницу.

Опять же, декораторы были доступны под флагом, но теперь, когда декораторы фактически доходят до стадии 3, потребуется повторная реализация и поломка кода для TypeScript. Вот почему эти вещи _нельзя_ считать вероятными.

async/await также был представлен в TypeScript на ранней стадии.

Как только предложение ECMAScript достигло этапа 3.

Никто не хулиганит, но если этот разговор никуда не может пойти, кроме как по кругу (а что, если бы был флаг? Да, мы в курсе о флагах) или не по теме (а что, если TS перестанет быть JS? Нет, пять лет спустя мы не меняемся наш ум об этом), нам не нужно иметь это. Мы говорили уже около 3 лет, что мы реализуем это именно тогда, когда комитет ES заблокирует его семантику.

Еще раз, репозиторий предложения https://github.com/tc39/proposal-Optional-Chaining , и вы можете следить за его ходом там. Мы будем работать в автономном режиме, чтобы попытаться улучшить шансы предложения на следующем собрании TC39, потому что мы действительно хотим, чтобы это тоже прошло.

Обновление: Сегодня днем ​​на TC39 мы достигли этапа 2!!!

Необязательная цепочка - это этап 3

Кратковременно разблокировать этот только для праздничных целей

Ура!

Не спамить...

Вы можете отправить смайлик, выражающий ваши чувства

Не спамить...

Вы можете отправить смайлик, выражающий ваши чувства

Кроме того, забавно наблюдать, как растет количество смайликов. Я никогда не видел, чтобы комментарий к проблеме так быстро набирал популярность!

Я записал небольшое видео об обновлениях в реальном времени https://youtu.be/JLBrgPjeGhc

Кто-нибудь может отписать меня от этой штуки?

@DanielRosenwasser Если вы не шутите, или для тех, кто хочет отписаться, но не знает как, вы ищете эту кнопку на правой боковой панели:

image

Не говоря уже о том, что в письме есть ссылка:

image

Это была шутка, я работаю над предложением.

@RyanCavanaugh после разблокировки этой проблемы:
martian

Действительно рад видеть, что это, наконец, земля! 🎈 🎉

Не могу дождаться соответствующего быстрого исправления VSCode 😆

image

Я собираюсь @ @RyanCavanaugh, потому что он, вероятно, отписался от этой темы, и я хочу быть грубым! (и @DanielRosenwasser на всякий случай)

@kitsonk Не будь ослом. Люди могут отказаться от подписки и не подвергаться преследованиям.

@kitsonk , почему RyanCavanaugh или DanielRosenwasser отписываются от этой темы? Райан разблокировал эту проблему, а Даниэль ответил на три комментария над вами.

Даже если они были отписаны, нет необходимости создавать дополнительную усталость от уведомлений, рассылая их спамом.

Судя по всему, GitHub — ужасное место для саркастичного юмора, господи…

Большое спасибо нашим чемпионам на TC39 за то, что они выяснили неприятные детали этой новой языковой функции!

thanks

Я думаю, что @kitsonk просто пошутил, как и я. Хотя мы немного глупо относимся к волнениям, это мягкое напоминание о том, что нужно вести себя цивилизованно в соответствии с CoC.

@ДаниэльРозенвассер
Может, мне стоит попробовать это? Или у @rbuckton есть еще одна существующая ветка для этого 🙋🏻‍♂️


Хорошо, я понял https://github.com/microsoft/TypeScript/commits/OptionalChainingStage1 🤦🏻‍♂️

Да, это уже устарело, к сожалению.

Я только что понял, что этот вопрос открыт 5 лет назад. :пораженный:

@рбактон

Да, это уже устарело, к сожалению.

Могу ли я попробовать это?

Извините , @jhpratt @MatthiasKunnen, я забыл, что мы не все используем один и тот же контекст на GitHub. Я слонялся здесь долгое время, провел время с Райаном и Дэниелом в реальной жизни и немного поучаствовал в недавнем событии, которое породило мою непонятую внутреннюю шутку. Извинения.

Тем не менее, весь этот выпуск демонстрирует интересную археологию принципов проектирования TypeScript. Райан поднял этот вопрос в то время, когда TypeScript _может_ фактически рассматривал синтаксис, который предшествовал серьезному рассмотрению в ECMAScript. Примерно в то же время внутри TypeScript извлекали некоторые уроки предсказания синтаксиса ES2015, которые оказали серьезное влияние на язык. Команда решила не рассматривать включение до тех пор, пока не появится предложение TC39 Stage 3.

Хотя @RyanCavanaugh может решить эту проблему, и я знаю, что он был близок к тому, что произошло с предложением, я подозреваю, что маловероятно, что то, что команда реализовала бы еще в 2014 году, было бы на 100% совместимо с текущим предложением Этапа 3. . Так что, хотя это, безусловно, праздник, также будьте благодарны, что у нас нет 5-летнего кода TypeScript с безопасным оператором навигации, который не полностью соответствовал бы поведению в предложении.

🙏

westwing

Не пора ли убрать ярлык «Ожидание TC39» ? 🤔

И добавьте ship-it

вау-вау-вау

Ну наконец то. Буквально расспрашивал о дополнительных цепочках, интересно, когда будет этап 3, и бац! Спасибо всем, кто работал над его завершением!

Как заглушить эту тему? :)

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

image

image

Любое решение для эмиссии уже определено?
Что-то вроде этого может быть интересно:

function __chain<T extends object, U>(value: T|null|undefined, callback: (value: T) => U): U|undefined {
    if (value !== null && value !== undefined) {
        return callback(value);
    }

    return undefined;
}

type Foo = { x?: { y?: { z?: () => number } } }

const foo: Foo|null = { }

// foo?.x?.y?.z?()
const value = __chain(foo, _a => __chain(_a.x, _b => __chain(_b.y, _c => __chain(_c.z, _d => _d()))));

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

var _foo, _foo$x, _foo$x$y, _foo$x$y$z;

// foo?.x?.y?.z?.()
(_foo = foo) === null || _foo === void 0 ? void 0
    : (_foo$x = _foo.x) === null || _foo$x === void 0 ? void 0
    : (_foo$x$y = _foo$x.y) === null || _foo$x$y === void 0 ? void 0
    : (_foo$x$y$z = _foo$x$y.z) === null || _foo$x$y$z === void 0 ? void 0
    : _foo$x$y$z.call(_foo$x$y);

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

var _foo, _foo$x, _foo$x$y, _foo$x$y$z;

// foo?.x?.y?.z?.()
(_foo = foo) === null || _foo === void 0 ? void 0
  : (_foo$x = _foo.x) === null || _foo$x === void 0 ? void 0
  : (_foo$x$y = _foo$x.y) === null || _foo$x$y === void 0 ? void 0
  : (_foo$x$y$z = _foo$x$y.z) === null || _foo$x$y$z === void 0 ? void 0
  : _foo$x$y$z.call(_foo$x$y);

Я согласен, @ExE-Boss. Я считаю, что идеально избегать создания ненужных областей действия функций (даже если это делает скомпилированный код немного уродливым).

Когда мы говорим о скомпилированном коде, производительность и соответствие спецификации ES определенно должны преобладать над удобочитаемостью.

Есть ли какая-то причина, по которой код, скомпилированный Babel, сравнивается как с null , так и с void 0 с тройным равенством вместо простого == null ?

Есть ли какая-то причина, по которой код, скомпилированный Babel, сравнивается как с null , так и с void 0 с тройным равенством вместо простого == null ?

@proteria Я только что взглянул на необязательный код цепочки для __Babel__ ; кажется, что если вы передадите параметр loose и установите для него истинное значение, он не будет производить строгие проверки на равенство

Это из-за document.all (или, если быть педантичным, внутреннего слота [[IsHTMLDDA]] ), причуды, которая получает специальную обработку в языке для обратной совместимости.

document.all == null // true
document.all === null || document.all === undefined // false

В необязательном предложении цепочки

document.all?.foo === document.all.foo

но document.all == null ? void 0 : document.all.foo неправильно возвращает void 0 . В свободном режиме эта деталь спецификации отбрасывается из-за простоты/производительности/размера сгенерированного кода, поскольку большинству людей все равно не приходится иметь дело с document.all .

Конечно, случай document.all может быть особенным? Это не должно требовать много дополнительного кода, всего несколько строк для проверки объекта и свойства.

За исключением того, что document.all может быть присвоено переменной, а отслеживание того, где оно используется, требует системы типов, поэтому Babel выводит по умолчанию:

(_prop = prop) === null || _prop === void 0 ? void 0 : _prop./* do stuff */;

Я знаю об этом. В Babel нет системы типов, в отличие от TypeScript. Возможно, это не так просто, как мне кажется, но я полагаю, что уже есть код для определенных ситуаций, способный отслеживать использование.

На самом деле вам не нужна система типов для отслеживания переменных document.all , поскольку особое поведение на самом деле относится к HTMLAllCollection , а не к document.all .

Так что вы должны просто сделать проверку на instanceof HTMLAllCollection , и вы станете золотым.

Да, но... зачем ты сделал instanceof , когда можешь просто сделать === null || === void 0 ? Наверняка это проще.

Точно - я просто указал, что вам не нужна система типов для отслеживания document.all :)

Лично у меня возникает соблазн просто сломать его и посмотреть, кто жалуется, но это указано в спецификации, поэтому проще всего придерживаться этого.

@noppa Это можно выполнить во время компиляции. Если foo instanceof HTMLAllCollection равно true , выдать foo === null || foo === void 0 , иначе мы можем _безопасно_ выдать foo == null .

@ G-Rath Нравится вам это или нет, устаревшее не означает, что оно не должно работать. TypeScript должен оставаться совместимым с JavaScript.

@jhpratt Но в настоящее время это противоречит нецелям дизайна TypeScript .

Кроме того, вам все равно придется делать foo === null || foo === void 0 для всего, чему может быть назначено HTMLAllCollection , например. any или object , поэтому я не думаю, что оно того стоит.

Я полагаю, вы имеете в виду не цель (5)

Добавляйте или полагайтесь на информацию о типах во время выполнения в программах или генерируйте другой код на основе результатов системы типов. Вместо этого поощряйте шаблоны программирования, не требующие метаданных времени выполнения.

Хотя я согласен, что это, безусловно, будет генерировать другой код в зависимости от типа, это только для уменьшения размера кода. Хотя, как вы указали, это не так просто, как проверка HTMLAllCollection .

Справедливости ради следует отметить, что TS _has_ отклонил потенциальный минификатор, который использует информацию о типе, и это (в некотором роде) связано — основная причина выдачи == null заключается в уменьшении размера кода на основе информации о типе.

Если это _не_ реализовано, было бы здорово, если бы команда lang добавила в tsconfig параметр, аналогичный "свободному" параметру Babel.

После быстрой проверки terser автоматически преобразует foo === null || foo === undefined в foo == null , что небезопасно из-за этого пограничного случая.

Если это не реализовано, было бы здорово, если бы команда lang добавила в tsconfig параметр, аналогичный параметру Babel «loose».

Соответственно, многие из нас используют TypeScript для инструментов сборки и мобильных приложений, и никому из них не нужно беспокоиться об ограничениях браузера!

На самом деле мы используем и TS, и Babel вместе, поэтому, возможно, одним из этих вариантов должен быть перенос оператора в Babel/базовую среду выполнения!

@fbartho

На самом деле мы используем и TS, и Babel вместе, поэтому, возможно, одним из этих вариантов должен быть перенос оператора в Babel/базовую среду выполнения!

Я не понимаю этот комментарий. Вам не нужны никакие дополнительные опции для передачи оператора в Babel; если у вас настроен TypeScript для Babel, у вас уже есть noEmit: true , который уже передает _все_ в Babel.

В реализации TypeScript @Zarel Babel отсутствуют несколько функций, на которые уже полагалась наша кодовая база, включая пространства имен и константные перечисления. Мы используем TSC с включенным излучением и применяем Babel в качестве второго преобразования. (Мы работаем над тем, чтобы избавиться от пространств имен, но неясно, сможем ли мы когда-нибудь избавиться от всех несоответствующих функций)

Людям, заходящим в эту ветку, следует начинать с более раннего объявления этапа 3 и читать комментарии, начинающиеся там (обвините GitHub в том, что он скрывает тонны пользовательского контента без простого способа загрузить все)

Отличная функция - "необязательная цепочка" / "безопасная навигация". Особенно в строгом режиме TypeScript. Приятно слышать, что это будет реализовано в ближайшее время. ❤️

Это привело меня сюда, и я надеюсь, что это будет поддержано. Просто вариант использования:

Ожидается в TypeScript 3.7.

document.querySelector('html')?.setAttribute('lang', 'en');

ПРОТИВ

В настоящее время в TypeScript 3.5.

const htmlElement = document.querySelector('html');
if (htmlElement) {
  htmlElement.setAttribute('lang', 'en');
}

Будет ли это работать без ошибок? Или это все еще TypeError: Cannot read property 'setAttribute' of null. ? ? op. следует отменить дальнейшие цепочки после null/undefined.

class Test {
  it() {
    console.log('One');
    document.querySelector('html')?.setAttribute('lang', 'en');
    console.log('Two');
  }
}
new Test().it();

Я ожидаю следующее:
Если элемент html не существует (нулевой). Консоль должна регистрировать One и Two , а метод setAttribute не вызывается. (без ошибок).
Я правильно это понял?

@domske К вашему сведению, это не строго функция TS; это функция JS.

Согласно предложению TC39 синтаксис будет следующим:

document.querySelector('html')?.setAttribute?.('lang', 'en');

Обсуждение снова начало идти по кругу, поэтому мы вернулись в заблокированное состояние.

Я искренне прошу всех, кто испытывает искушение оставить комментарий в ветке GitHub длиной более 100 комментариев, действительно взять на себя обязательство сначала прочитать все предыдущие комментарии. Возможно, ваш вопрос и ответ на него найдутся там!

Была ли эта страница полезной?
0 / 5 - 0 рейтинги