Почему методы со стрелками не разрешены в Typescript?

Предложения разрешить методы стрелок в Typescript были отклонены на основании «изменения Javascript как языка». Как именно изменить язык, чтобы в объявлении функции было на один символ меньше (см. add2 и add3 в примере ниже)?

Это особенно сбивает с толку, учитывая все другие изменения, которые Typescript накопил по сравнению с Javascript за эти годы.

export class Point {
    constructor(public x: number, public y: number) {
        this.x = x
        this.y = y
    }

    add1(p: Point): Point {
        return new Point(this.x + p.x, this.y + p.y)
    }

    add2 = (p: Point) => new Point(this.x + p.x, this.y + p.y)

    add3(p: Point) => new Point(this.x + p.x, this.y + p.y)
    
    ...

РЕДАКТИРОВАТЬ

Добавлены ссылки на некоторые предложения

① Не могли бы вы дать ссылку на эти предложения в своем вопросе? Предположительно авторитетный ответ на этот вопрос можно найти в ответах группы TS по этим вопросам.

jcalz 12.05.2023 16:57

② У языка TypeScript есть цели проектирования, которые на данный момент по существу запрещают внесение каких-либо изменений, наблюдаемых во время выполнения, если только они не являются частью предстоящего предложения для самого JavaScript. Методы со стрелками, если они являются хорошей идеей, должны быть реализованы в JS, и TS поддержит их, когда они достигнут этапа 3 в процессе предложения TC39. Старые изменения TS, которые нарушают это, по сути, являются артефактами более ранней эпохи, когда эти цели еще не закрепились. Я был бы рад написать ответ об этом, но я хотел бы, чтобы ① ответил первым.

jcalz 12.05.2023 17:12

Просто на заметку, вы знаете это, потому что ваше использование this, add1() — единственное, что имеет смысл, иначе вы потеряете преимущества prototype.

Keith 12.05.2023 17:16

@jcalz github.com/microsoft/TypeScript/issues/…

Anton Duzenko 13.05.2023 21:17

@ Кит, ты расскажешь, что именно я теряю add2() - для меня это просто работает

Anton Duzenko 13.05.2023 21:18

Извините, я имел в виду, что вы должны отредактировать свой вопрос, чтобы сослаться на них. Кроме того, проблема, на которую вы ссылаетесь, касается методов доступа (например, get foo() {}, к которым можно получить доступ, как x.foo), а не методов, поэтому это не то же самое, о чем вы говорите здесь. Есть ли какой-то фактический запрос на «методы стрелочных функций»? В вашем вопросе написано «предложения», поэтому я ожидаю увидеть более одной ссылки. Это опечатка, и вы просто имели в виду "предложение"?

jcalz 13.05.2023 21:22

@jcalz Я ценю ваши отзывы. Отредактировал текст вопроса, но в основном я исхожу из этого поиска: github.com/microsoft/TypeScript/…. Мы не можем согласиться с тем, что геттеры - это методы?

Anton Duzenko 14.05.2023 10:39

@AntonDuzenko Потому что add2 не добавляет свой метод в прототип, вместо этого он добавляет его в каждый экземпляр класса. IOW: Если вы создали миллион экземпляров Point, будет миллион экземпляров метода add2, но поскольку add1 является методом-прототипом, он создается только один раз. Это как бы вся цель прототипа класса и this.

Keith 14.05.2023 15:34

Так что ms/TS#18500 однозначно актуален. Он был закрыт, заявив, что они не принимают такие запросы функций, потому что не хотят беспокоиться о конфликтах с будущими изменениями в JS. Это функция времени выполнения, поэтому они хотят сначала увидеть ее в JS, а затем будут ее поддерживать. В противном случае происходит то же самое, что с полями классов и декораторами: ранняя реализация TS конфликтовала с более поздней JS, и ее нужно было полностью переделывать. Эти функции разумны, но ребята из TS на собственном горьком опыте усвоили, что любые изменения во время выполнения должны исходить в первую очередь из JS.

jcalz 14.05.2023 16:15

^ Это полностью отвечает на вопрос? Если да, то я напишу это как ответ. Если нет, то что мне не хватает?

jcalz 14.05.2023 16:17

@jcalz Я так думаю

Anton Duzenko 14.05.2023 21:36
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
0
11
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Потому что в Javascript (и, следовательно, в Typescript) стрелочные функции не имеют контекста this, и это не имеет смысла для методов класса.

add2 транспилируется в

class Point {
    constructor(...a) {
        this.add2 = (p: Point) => new Point(this.x + p.x, this.y + p.y);
    }
}

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

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

Anton Duzenko 12.05.2023 17:37

И я не уверен, что вы имеете в виду вообще - эта функция просто работает для меня

Anton Duzenko 13.05.2023 21:19

@AntonDuzenko just works for me, если вы довольны тем, что каждый экземпляр Point имеет замыкание над собственной копией функции, то это нормально.

Keith 14.05.2023 15:47
Ответ принят как подходящий

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


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

Методы стрелок являются функциональностью времени выполнения и будут наблюдаться во время выполнения, поскольку предположительно написание

add3(p: Point) => new Point(this.x + p.x, this.y + p.y);

нужно будет транспилировать либо

add3 = (p) => new Point(this.x + p.x, this.y + p.y);

или, может быть

add3(p) { return new Point(this.x + p.x, this.y + p.y); }

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

И методы со стрелками не предназначены для внедрения в JavaScript. Поэтому по этим причинам предложение добавить это в TypeScript будет отклонено, как вы видели в microsoft/TypeScript#18500.


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

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

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

Это большая головная боль для языка.

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

Каким бы хорошим ни было предложение, если JavaScript может либо реализовать его, либо помешать ему, TypeScript почти наверняка отклонит его.


Итак: если методы со стрелками — хорошая идея для TypeScript, они также будут хорошей идеей для JavaScript (за исключением аннотаций типов, поэтому во время выполнения это будет выглядеть как add3(p) => new Point(this.x + p.x, this.y + p.y)). И поэтому заинтересованным и заинтересованным сторонам следует рассмотреть возможность внесения такого предложения в TC39. Если он будет принят, TypeScript обязательно его поддержит.

Вы, безусловно, вложили гораздо больше в ответ, который я вложил в вопрос

Anton Duzenko 15.05.2023 19:13

Другие вопросы по теме