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

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

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

Я воспроизвел проблему с помощью этого простого кода:

class Greeter {
    private _greetings: string[];
    constructor () {}
    set greetings(greetings: string[]) {
        let newGreetings: string[] = [];
        for (let i: number = 0; i < greetings.length; i++) {
            newGreetings.push("setter_" + greetings[i] )
        }
        this._greetings = newGreetings;
    }

    get greetings() {
        return this._greetings;
    }
}

let greeter = new Greeter();
greeter.greetings = ["test"];
let test1 = document.createElement('p');
test1.textContent = greeter.greetings[0];
document.body.appendChild(test1);

greeter.greetings[0] = "test";
let test2 = document.createElement('p');
test2.textContent = greeter.greetings[0];
document.body.appendChild(test2);

Чтобы просмотреть код на игровой площадке TS, перейдите по ссылке ниже:

https://www.typescriptlang.org/play/#src=class%20Greeter%20%7B%0D%0A%20%20%20%20private%20_greetings%3A%20string%5B%5D%3B%0D%0A%20%20%20%20constructor%20()%20%7B%7D%0D%0A%20%20%20%20set%20greetings(greetings%3A%20string%5B%5D)%20%7B%0D%0A%09%09let%20newGreetings%3A%20string%5B%5D%20%3D%20%5B%5D%3B%0D%0A%09%09for%20(let%20i%3A%20number%20%3D%200%3B%20i%20%3C%20greetings.length%3B%20i%2B%2B)%20%7B%0D%0A%09%09%09newGreetings.push(%22setter_%22%20%2B%20greetings%5Bi%5D%20)%0D%0A%09%09%7D%0D%0A%09%09this._greetings%20%3D%20newGreetings%3B%0D%0A%09%7D%0D%0A%09%0D%0A%09get%20greetings()%20%7B%0D%0A%09%09return%20this._greetings%3B%0D%0A%09%7D%0D%0A%0D%0A%7D%0D%0A%0D%0Alet%20greeter%20%3D%20new%20Greeter()%3B%0D%0Agreeter.greetings%20%3D%20%5B%22test%22%5D%3B%0D%0Alet%20test1%20%3D%20document.createElement(

У меня вопрос: я что-то не так делаю? Это предполагаемое поведение? Или это больше проблема с компилятором машинописного текста, который не должен позволять компилировать этот код?


person user1769949    schedule 26.07.2016    source источник
comment
Какая именно часть является неожиданной в этом?   -  person Ryan Cavanaugh    schedule 26.07.2016
comment
Я ожидаю, что в обоих случаях значение будет: setter_test   -  person user1769949    schedule 27.07.2016


Ответы (1)


Глядя конкретно на эти две строки:

greeter.greetings = ["test"];

а также

greeter.greetings[0] = "test"

Они внешне похожи, но на самом деле очень разные. В этой строке говорится, что задайте для свойства greetings элемента greeter значение ["test"]. Сеттер greetings вызывается, потому что мы устанавливаем свойство greetings.

greeter.greetings = ["test"];

Напротив, эту строку следует рассматривать как две операции

// this line...
greeter.greetings[0] = "test"
// ...is the same as
const tmp = greeter.greetings;
tmp[0] = "test";

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

Начиная с TypeScript 2.0 (в бета-версии на момент написания статьи) вы сможете использовать ReadonlyArray<string> для представления массивов, которые можно читать, но нельзя записывать. Это позволит вам показывать ReadonlyArray<string> потребителям, но иметь обычное string[] в качестве поля private.

person Ryan Cavanaugh    schedule 26.07.2016
comment
Это имеет смысл — спасибо, что нашли время объяснить это новичку в машинописи. - person user1769949; 27.07.2016