Интерфейс действует так, как если бы он был указателем - PullRequest
0 голосов
/ 15 июня 2019

У меня есть интерфейс (A), с интерфейсом внутри (B). Интерфейс A используется в качестве массива интерфейса A.

Когда я обновляю интерфейс B в определенном интерфейсе A, ВСЕ тот же интерфейс B в любом интерфейсе A также обновляется.

Если я использую тот же метод, но устанавливаю атрибут интерфейса A, это правильно.

Я, например, сделал умный код.

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

Клиент как продукт, eatByMinute и howMany (howMany Client). Ферма как продукт, makeByMinute (сколько продукта делают за минуты).

Я добавляю «Интерфейс фермы» в «Интерфейс клиента» для получения большого объекта данных. А мне что посчитать "Сколько ферм мне нужно".

Если я установлю HowManyNeed в «Интерфейс фермы», все одинаковые «Интерфейс фермы» во всех «Интерфейс клиента» примут одно и то же значение.

Если я установлю HowManyFarmNeed в «Интерфейсе клиента», каждое значение будет правильным

Логика:

Init-> Пуск-> CountFarmNeed-> конец


    const farms: IFarm[] =
        [{
            "name": "AppleFarm",
            "product": "Apple",
            "makeByMinute": 2
        }, {
            "name": "PerryFarm",
            "product": "Perry",
            "makeByMinute": 1
        }
        ];

    interface IFarm {
        name: string,
        product: string,
        makeByMinute: number,
        howManyNeed?: number
    }

    interface IClient {
        name: string,
        eatByMinute: number,
        whatDoesEat: string,
        howMany: number,
        farm?: IFarm,
        howManyFarmNeed?: number
    }

    export class Client {
        static get(name: string, eatByMinute: number, whatDoesEat: string, howMany: number): IClient {
            return {name: name, 'eatByMinute': eatByMinute, 'whatDoesEat': whatDoesEat, 'howMany': howMany}
        }
    }

    export class Farm {
        static getByProduct(product: string): IFarm {
            //@ts-ignore: array.Find can return "Undefined" BUT function return IFarm. In this exemple is ok
            return farms.find((item: IFarm) => item.product == product);
        }
    }

    export default class Problem {
        static init() {
            let clients: IClient[] = [
                Client.get('men', 0.25, 'Apple', 2000),
                Client.get('women', 0.30, 'Perry', 1500),
                Client.get('dog', 0.25, 'Apple', 3000),
            ];
            clients = this.start(clients);
            clients = this.countFarmNeed(clients);
            this.end(clients)

        }

        static start(clients: IClient[]):IClient[] {
            for (let c in clients) {
                clients[c] = this.loadFarm(clients[c]);
            }
            return clients
        }

        static loadFarm(client: IClient): IClient {
            client.farm = Farm.getByProduct(client.whatDoesEat);
            return client;
        }

        static countFarmNeed(clients: IClient[]):IClient[] {
            for (let c in clients) {
                //@ts-ignore: clients[].farm possibly undifined. In this exemple is ok
                clients[c].farm.howManyNeed = (clients[c].howMany * clients[c].eatByMinute) / clients[c].farm.makeByMinute;
                //@ts-ignore: clients[].farm possibly undifined. In this exemple is ok
                clients[c].howManyFarmNeed = (clients[c].howMany * clients[c].eatByMinute) / clients[c].farm.makeByMinute;
            }
            return clients
        }

        static end(clients:IClient[]){
            console.log(clients)
        }
    }

Я ожидаю

[0].farm.howManyNeed:250;
[1].farm.howManyNeed:450;
[2].farm.howManyNeed:375;

Но на самом деле имеет:

[0].farm.howManyNeed:375;
[1].farm.howManyNeed:450;
[2].farm.howManyNeed:375;

1 Ответ

0 голосов
/ 16 июня 2019

Ваша проблема в том, что clients[0].farm и clients[2].farm относятся к одному и тому же объекту, поэтому, конечно, они будут иметь одинаковое значение howManyNeed свойство. Функция countFarmNeed() заменяет любое предыдущее изменение на farm.howManyNeed, если новое client имеет то же farm.

Если вы хотите иметь два разных объекта, вам нужно будет сделать копию объекта farm из массива farms вместо того, чтобы просто возвращать его, как в:

const Farm = {
  getByProduct(product: string): IFarm {
    // don't use ts-ignore for trivial type checking like this
    const farm = farms.find((item: IFarm) => item.product == product);
    // throw a runtime error if you get a problem, and TS understands tihs
    if (!farm) throw new Error("Failed to find farm for " + product);
    // if you get here, then farm is not undefined
    return Object.assign({}, farm); // copy of the farm
  }
};

Здесь я использовал Object.assign(), чтобы скопировать свойства из farm в новый объект перед его возвратом. Теперь вы получите ожидаемые результаты.

Ссылка на код

Обратите внимание, что в остальной части кода есть некоторые проблемные вопросы, которые вы, возможно, захотите решить:

  • Не использовать // @ts-ignore комментарии для подавления ошибок простой проверки типов. Это излишне и может иметь странные побочные эффекты. Если все, что вы делаете, это утверждает, что что-то не undefined, вы можете просто использовать оператор ненулевого подтверждения (!) или просто пойти и проверить его на undefined во время выполнения и полагаться на анализ потока управления TypeScript , чтобы исключить возможность.

  • Вы, похоже, используете class, чтобы содержать только static методов, что странно. Вместо этого вы можете просто использовать простой старый объект (class Foo {static bar() {}} становится const Foo = {bar() {}}) или даже namespace или module, если вы просто пытаетесь дать имя группе из связанные вещи.

  • обычно не рекомендуется перебирать массив, используя цикл for...in. Рассмотрим более традиционный метод итерации, такой как for...of loop .

  • Объекты с именами ключей, как правило, легче понять, чем список параметров. Ваш Client.get(a,b,c,d) метод гораздо более запутанный, чем просто использование объектных литералов, таких как { name: a, eatByMinute: b, whatDoesEat: c, howMany: d }. В первом случае разработчик должен помнить порядок параметров и не передавать whatDoesEat в течение name (они оба string s). В последнем нет порядка беспокоиться.

Я пока остановлюсь там. Надеюсь, что это поможет вам. Удачи!

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