【问题标题】:Interface acts as if he was a pointer接口就像一个指针一样
【发布时间】:2019-06-15 08:12:47
【问题描述】:

我有一个接口 (A),里面有一个接口 (B)。接口 A 用作接口 A 的数组。

当我更新特定接口 A 中的接口 B 时,任何接口 A 中的所有相同接口 B 也会更新。

如果我使用相同的方法但设置了一个接口A属性,是正确的。

例如,我制作了一个智能代码。

我们让客户分分钟吃掉一些 x 产品。我需要知道我需要多少个农场才能配得上所有的客户。

Client 作为产品,eatByMinute 和 howMany(howMany Client)。 作为产品的农场,makeByMinute(按分钟制造多少产品)。

我在“客户端界面”中注入“农场界面”以获取大数据对象。我要计算“我需要多少个农场”。

如果我在“农场接口”中设置 HowManyNeed,则所有“客户端接口”中的所有相同“农场接口”都采用相同的值。

如果我在“客户端界面”中设置了 HowManyFarmNeed,则每个值都是正确的

逻辑是:

初始化->开始->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;

【问题讨论】:

    标签: typescript pointers interface


    【解决方案1】:

    您的问题是 clients[0].farmclients[2].farm 引用同一个对象,所以它们当然将具有相同的值 howManyNeed 属性。如果新的client 具有相同的farmcountFarmNeed() 函数将覆盖对farm.howManyNeed 的任何早期更改。

    如果您想拥有两个不同的对象,则必须从farms 数组中制作farm 对象的副本,而不是仅仅返回它,如下所示:

    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 复制到一个新对象中,然后再返回它。现在你会得到你期望的结果。

    Link to code

    请注意,其余代码有一些您可能想要解决的麻烦问题:

    • 不要使用// @ts-ignore comments 来抑制简单的类型检查错误。这太过分了,可能会产生奇怪的副作用。如果您所做的只是断言某些东西不是undefined,您可以只使用non-null assertion operator (!),或者继续在运行时检查undefined,并依靠TypeScript 的control flow analysis 来消除这种可能性。

    • 您似乎使用class 只包含static 方法,这很奇怪。相反,如果您只是想为一组相关的事物命名,则可以只使用一个普通的旧对象(class Foo {static bar() {}} 变为 const Foo = {bar() {}})甚至是 namespace or module

    • 使用for...in 循环遍历数组是generally discouraged。考虑一种更传统的迭代方法,例如 afor...of loop

    • 带有键名的对象通常比参数列表更容易理解。你的Client.get(a,b,c,d) 方法比仅仅使用像{ name: a, eatByMinute: b, whatDoesEat: c, howMany: d } 这样的对象字面量更令人困惑。在前者中,开发人员需要记住参数的顺序,而不是将whatDoesEat 传递给name(它们都是strings)。后者无需担心顺序。

    我现在就到此为止。希望对您有所帮助。祝你好运!

    【讨论】:

    • 感谢您的所有建议!我学习打字稿:) 如果它能让你放心,我从不在我的代码中使用@ts-ignore。如果我的 IDE 说我犯了一个错误.. 我相信他 ^^' 非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2012-08-04
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多