Можно ли реализовать разные модификаторы доступа для геттера и сеттера? Таким образом, сеттер может быть, например, закрытым/защищенным, а геттер общедоступным. В некоторых случаях это действительно полезно, когда значение должно быть доступно только для чтения.
Пример:
class MyClass {
private _myProp: any;
private set myProp(value: any) {
this._myProp = value;
}
public get myProp(): any {
return this._myProp;
}
}
Поскольку № 12 закрыт с № 6532, теперь кажется, что эта проблема выходит за рамки.
Есть ли у вас какие-либо планы по внедрению различных модификаторов доступа?
Потому что readonly
недостаточно для решения того, что здесь описано, поскольку свойство может быть действительно доступным для записи внутри класса.
Я считаю, что мне также следует перенести сюда мой пример из связанной проблемы:
declare abstract class Emitter {
new (): Emitter;
on: (name:string, handler: (arg:any) => void) => void;
off: (name:string, handler: (arg:any) => void) => void;
protected emit: (name:string, arg:any) => void;
}
class Person extends Emitter {
constructor(name:string) {
super();
this.name = name;
}
private _name:string;
get name() {
return this._name;
}
set name(value) {
if (this._name !== value) {
this._name = value;
this.emit('change:name', value);
//this way is better
this.updatedAt = new Date();
//than this way
this.setUpdatedAt(new Date());
}
}
////
private _updatedAt:Date;
get updatedAt() {
return this._updatedAt;
}
private set updatedAt(value) { //Getter and setter do not agree in visibility
//some logic and a simple readonly (our absence of a setter) is not enough
if (this._updatedAt !== value) {
this._updatedAt = value;
this.emit('change:updatedAt', value);
}
}
//// method implementation - but what's the point in it?
private setUpdatedAt(value) {
if (this._updatedAt !== value) {
this._updatedAt = value;
this.emit('change:updatedAt', value);
}
}
}
const entity = new Person('Mike');
entity.on('change:updatedAt', console.log.bind(console));
entity.name = 'Thomas';
//but manually setting updatedAt should be forbidden
entity.updatedAt = new Date(); //restricted
Здесь свойство updatedAt
на самом деле может иметь сеттер, но оно не должно быть доступно за пределами Person
. Кроме того, этот сеттер содержит сложную логику, и простого readonly или отсутствия сеттера недостаточно.
Я согласен с тем, что частный сеттер - это просто синтаксический сахар для частных методов с дополнительной логикой (например, испускание), но я думаю, что это непоследовательно, когда часть логики, связанная с полем, находится в свойстве (геттер), а другая - в методе (частный сеттер) .
Таким образом, геттеры/сеттеры реализованы в C#
, я думаю, было бы полезно разрешить различную видимость во время компиляции, хотя эти контракты будут потеряны во время выполнения.
Здесь рекомендуется использовать общедоступный геттер только для чтения и приватное/защищенное резервное поле.
Аксессоры симметричны свойствам в системе типов. все, что мы делаем, должно быть выражено в типе и выражено в свойствах. Добавление новых модификаторов доступа для включения private_set/public_get увеличило бы сложность языка и кривую обучения, а полученная от этого ценность не соответствовала бы добавленной сложности.
В любом случае добавлю мой +1 за это, на случай, если это будет рассмотрено снова в будущем...
Я все еще хотел бы увидеть это. В C# он есть, и он невероятно полезен во многих случаях, особенно когда у вас есть флаги, которые нужно считывать извне для класса, но устанавливаются только внутри с помощью private/protected.
Я думаю, что предположение о том, что он не используется так часто, является фарсом в том смысле, что шаблон не используется, потому что он недоступен для использования.
Это хорошее дополнение к языку: сложность, которую это добавит (с точки зрения программиста машинописи), невелика. Концепция проста для понимания, и компилятор должен быть в состоянии предоставить хорошие сообщения об ошибках, намекающие на то, почему вы не можете получить доступ к геттерам или сеттерам из-за области видимости.
Я согласен с вышеперечисленными пользователями, это стандартно для большинства других языков. Аргумент против этого не имеет веса, и реализацию следует пересмотреть.
Я вообще был удивлен, что вы не можете сделать это в TS... +1 к проблеме.
Не должно быть никакого увеличения кривой обучения с этим
private get x() { ... }
public set x(value) { ... }
Имо, если вы умеете читать по-английски, понятно, что здесь означает частное (защищенное) / общедоступное. Кроме того, если вы определяете средства доступа в первую очередь - вы, вероятно, уже знаете, для чего они нужны.
Ps Насчет ошибки: "Аксессуары геттера и сеттера не согласуются в видимости" - ну вот именно этого я и хочу от них
Вот два варианта использования, где это было бы удобно:
Backbone.js, чтобы избежать уродливых вызовов .get()
и .set()
:
class Whatever {
public get rotation(): number {
return this.get('rotation');
}
private set rotation(rotation: number) {
this.set('rotation', rotation);
}
}
Свойства, которые могут изменять подклассы:
class ExtendMe {
public get someProperty(): string {
// some stuff
}
protected set someProperty(prop: string) {
// some stuff
}
}
Я определенно хотел бы увидеть это, так как это беспокоило меня с тех пор, как я начал использовать TypeScript.
Я согласен с людьми, которые просят эту функцию. Я только что попробовал использовать общедоступный метод get() и был удивлен, увидев, что мой set и get должны согласовываться по видимости.
Я читал, что вы, ребята, утверждаете, что это слишком сложно. Вспоминая «способ С++», почему он отличается от:
private _myAttribute: string;
get myAttribute(): string {...}
setMyAttribute(value: string) {...}
Я вижу много вариантов использования для этого, поэтому я здесь прямо сейчас.
Что, если я хочу, чтобы myAttribute был общедоступным, но позволял изменять его только внутри своего класса?
Что, если я хочу добавить некоторую пользовательскую логику каждый раз при изменении атрибута?
Это может быть бизнес-правило, это может быть просто запись в журнал, чтобы понять, почему ему было присвоено определенное значение, вместе с условием точки останова для целей отладки и т. д.
По сути, мы хотим, чтобы метод использовался каждый раз, когда мы изменяем атрибут вместе с синтаксическим сахаром, который создает впечатление, что мы просто присваиваем значение, а не вызываем метод.
В C# есть концепция свойств для этого, и я думал, что TS унаследовал эту концепцию, но запрет на использование различных специальных возможностей является большим ограничением для людей, которые думают так же, как я, и заставляет нас вернуться к «стилю C++».
«Это слишком сложно» никогда не должно быть причиной, чтобы не реализовать невероятно полезную функцию.
Добавляю свой +1. Мне кажется очень странным, что в языке, столь совершенном во многих отношениях, вы не можете этого сделать.
Удивлен, обнаружив, что этот вопрос помечен как закрытый. Эта функция ЖЕЛАЕТ сообщество. Пожалуйста, снова откройте.
+1
ИМХО, это хорошая функция, но, насколько я понимаю, это просто ситуация «ну, я НЕ хочу писать каждый раз _property, вместо этого я хочу использовать частное заданное свойство»
Если есть выбор, либо добавляя огромную сложность к самому коду ядра TypeScript (помните, больше ненужной сложности - меньше скорость разработки, больше времени на отладку, написание тестов, в конце концов - менее частые релизы), но уменьшая написание 1 символа ИЛИ написание этот 1 символ и справляться с ним хорошо... Я бы предпочел писать 1 символ еще раз каждый раз. В конце концов, я не вкладываюсь в ядро TS, и я определенно не хочу разбираться с возможной сложностью этого сахара.
Ребята, это не нарушение условий сделки. Кроме того, требуется мужество и мудрость, чтобы признать запрос слишком сложным для реализации (с результатом, увеличивающим общую сложность кода), так что снимаю шляпу перед вами, ребята, разрабатывающие TypeScript, и спасибо за вашу работу!
(пс зашел узнать почему нет - в итоге передумал и буду разбираться с этим._property=...
и все равно будет доволен)
@idchlife Цель свойства set
состоит не в том, чтобы сэкономить разработчикам одно подчеркивание при присвоении значения. Вы также можете добавить некоторую логику в процесс set
.
Пожалуйста, откройте этот вопрос снова. Это явно очень желанная функция.
+1 Я бы хотел, чтобы это было пересмотрено.
Очень странно, что ваше обоснование заключается в том, что «это сбивает с толку», когда многие другие языки уже делают это.
Поскольку все 👍 мало что делают, я бы просто спамил еще одним 👍 комментарием.
Это был бы синтаксический сахар, который помогает сделать вещи более читабельными и быстрыми в реализации. Во многих языках есть синтаксический сахар, включая Typescript. Кажется, что нет никаких действительно веских причин, чтобы не делать этого, и слишком сложное никогда не является веской причиной, чтобы что-то не делать, это скорее ленивая отговорка. Решение слишком сложных проблем — одна из причин, по которым большинство людей привлекает разработка программного обеспечения. Так что возьмите эту сложную проблему и решите ее красивым, не таким сложным способом. Потребует ли это рефакторинга и рискованных изменений? Может быть, но именно так все и делается.
Еще желательно. Другие языки без проблем поддерживают различную видимость функций get и set. В довершение ко всему, Typescript создан Microsoft, как и C#, но последний полностью его поддерживает:
public string myPropertyWithLimitedAccess { get; private set; }
Посмотри на это. Красиво читается, и совершенно ничего сложного.
Мало причин не поддерживать:
private _myProperty: string;
public get myProperty(): string { return this._myProperty; }
private set myProperty(value: string) { this._myProperty = value; }
Бонусные баллы за странные дизайнерские решения, потому что Typescript был в первую очередь создан для разработчиков .NET, чтобы они привыкли работать с интерфейсом браузера.
+1
Typescript определенно выиграет от этой функциональности!
TypeScript великолепен даже после C#, но это бессмысленное ограничение довольно часто раздражает меня. Пожалуйста, откройте его снова.
увеличит сложность языка
Действительно ли это так сложно по сравнению с такими вещами, как readonly [P in keyof T]: T[P]
?
Удар. Все хотят эту функцию. Разве сообщество TypesScript не должно решать?
увеличит сложность языка
Действительно ли это так сложно по сравнению с такими вещами, как
readonly [P in keyof T]: T[P]
?
Сложность вступает в игру с взаимодействием других особенностей языка. К сожалению, я не могу найти его, но IIRC RyanCavanaugh привел пример, в котором эта функция может позволить вам установить, а затем нарушить инварианты через наследование с использованием выражения класса. Просто потому, что написать определенную декларацию легко, это не значит, что всегда будет легко рассуждать о том, как она влияет на вещи.
Вопрос в том, какие проблемы решит данная функция, а какие создаст. На первое ответить легко, на второе ответить на удивление сложно. К сожалению, команда TS иногда, кажется, отвечает «О боже, сложность» вместо того, чтобы проиллюстрировать проблему. (Честно говоря, чем больше времени они тратят на ответ на запрос x в n-й раз, тем меньше времени у них остается на разработку.)
Я не на 100% согласен с идеей «не должно ли решать сообщество», потому что если есть консенсус среди экспертов, фактически разрабатывающих язык, это должно вам кое-что сказать. Но я думаю, что с таким запросом, как это, вдумчивое объяснение от команды о том, в чем заключается компромисс и почему они против этого, не так уж много, чтобы просить.
И лично я думаю, что компромисс в данном случае оправдан на 1000%. Но если я не могу удосужиться его уточнить и заставить работать, полагаю, у меня нет особых прав на жалобы.
Не пора ли вернуться к этому вопросу?
Модификатор readonly
великолепен, но есть много случаев, когда вы хотите иметь возможность изменять значение внутри класса и по-прежнему иметь доступ только для чтения снаружи.
Я часто предпочитаю не делать свойство readonly
, потому что мне не нравится шум, который добавляет приватное резервное поле + свойства.
Было бы здорово, если бы для вас был синтаксический сахар. Что-то типа:
// Option 1: C# style
public name: string { get; private set; }
// Option 2: Swift style
private(set) name: string
// Option 3: Swift struct-style
public readonly name: string
mutating changeName(name: string) {
this.name = name
}
// Option 4: New keyword
public frozen name1: string
public readonly name2: string
Мне нравится вариант 2, имхо, он хорошо вписался бы в язык TypeScript.
С вариантом 3 вы можете изменять поля только для чтения только в функциях, помеченных как mutating
С опцией 4 frozen
можно установить только в конструкторе, readonly
можно установить внутри этого класса, а не какими-либо внешними классами или классами, унаследованными от этого класса.
Для справки, идеи @yvbeek о более гибких модификаторах лучше подходят для обсуждения в https://github.com/microsoft/TypeScript/issues/37487.
Эта проблема предназначена специально для геттеров и сеттеров и имеет очень большое количество голосов! Я думаю, было бы полезно дать геттерам и сеттерам разные модификаторы доступа (и мы можем обновить существующий набор модификаторов в # 37487, если команда TypeScript когда-либо решит, что это приемлемо для продвижения вперед)
Я не на 100% согласен с идеей «не должно ли решать сообщество», потому что если есть консенсус среди экспертов, фактически разрабатывающих язык, это должно вам кое-что сказать. Но я думаю, что с таким запросом, как это, вдумчивое объяснение от команды о том, в чем заключается компромисс и почему они против этого, не так уж много, чтобы просить.
@snarfblam Не хочу засорять эту ветку не относящимся к делу комментарием, но я думаю, что вы раскрыли основной принцип того, как должно работать правительство.
Отсутствие этой функции для меня настоящая боль и (среди прочего) заставило меня переключиться с TS/NodeJS на что-то более... безопасное для типов. Все бы ничего, но когда работаешь над сложным проектом с большим количеством структур данных (много раз глубоко вложенных) и не можешь правильно смоделировать данные, возникает ощущение, что это не язык "для больших мальчики».
В моем конкретном случае я хочу, чтобы свойство было доступно только для чтения, но могло быть изменено изнутри... а также сериализовано в JSON. Слишком много обручей, чтобы перепрыгнуть через них.
Эта функция может следовать тому же пути, что и _необязательная цепочка_. Люди будут просить об этой функции в течение многих лет, а затем, наконец, она будет добавлена в язык, потому что это практично, и другие языки предлагают ту же функцию.
В противном случае я надеюсь, что какая-то реализация станет частью EcmaScript, а затем попадет в TypeScript.
Недавно я просто перешел на машинопись, и мне очень понравился этот язык. Я очень расстроен тем, что эта практичная функция, существующая в других языках, не была реализована здесь. Пожалуйста, пересмотрите возможность добавления его в будущем выпуске, независимо от того, насколько сложным, по вашему мнению, может стать язык.
Я добился чего-то похожего на С# с геттерами таким образом:
export class I18nService {
private static ref: I18nService;
public static get instance(): I18nService {
if (!I18nService.ref) {
I18nService.ref = new I18nService();
}
return I18nService.ref;
}
}
Ошибки типов, подобные приведенным ниже, легко понять и не представляют сложности:
Property 'foo' is writable only in protected scope within class 'Blah' and its subclasses.
или
Property 'foo' is readable only in protected scope within class 'Blah' and its subclasses.
и т. д., и аналогично private
.
Вот честно не сложно.
Кстати, я тоже наткнулся на эту проблему, и тем временем я использую такой «хак»:
// somewhere.ts
declare global {
type Writable<T> = { -readonly [P in keyof T]: T[P]; }
}
// example.ts
class Example {
public readonly prop: number;
public doSomething(n: number): void {
(this as Writable<this>).prop = n;
}
}
Технически это можно использовать везде, но использование этого обходного пути должно быть ограничено кодом внутри методов класса.
Кстати, я тоже наткнулся на эту проблему, и тем временем я использую такой «хак»:
Я сам обдумывал эту идею, но проблема в том, что у вас нет способа отличить свойства «общедоступные только для чтения» от действительно доступных только для чтения свойств. Это делает его не очень подходящим в качестве универсального решения.
Самый полезный комментарий
В любом случае добавлю мой +1 за это, на случай, если это будет рассмотрено снова в будущем...