“默认对象”以初始化打字稿上的嵌套对象?

时间:2020-09-30 20:20:27

标签: javascript typescript object

我在打字稿上有以下对象来控制体育比赛的结果:

export interface IResult {
    [day: string]: IResultDay;
}

interface IResultDay {
    [matchId: string]: IMatch;
}

interface IMatch {
    teams: ITeam[];
    winner: ITeam;
    winnerScore: number;
    loserScore: number;
}

我之所以这样构建它,是因为它可以过滤“天”和“ matchId”中要查看的匹配项。

问题是,当我要构建该对象时,需要继续验证每个级别上的对象是否不是undefined。如果我不这样做,则会发生以下情况:

const result: IResult = {}; // init the first level
result['2020-09-30']['2020093012344321'] = {
  teams: [
    {
      teamId: '1234',
      teamName: 'Lakers'
    },
    {
      teamId: '4321',
      teamName: 'Miami Heat'
    }
  ],
  winner: {
    teamId: '1234',
    teamName: 'Lakers'
  },
  winnerScore: 117,
  loserScore: 107
};

错误:

TypeError: Cannot set property '2020093012344321' of undefined

当我深入嵌套对象时,情况变得更糟。是否有一种无需初始化每个级别即可构建该对象的方法?

在python中,字典上有此技巧,可让我们同时启动多个级别:

from collections import defaultdict
my_dict = defaultdict(lambda: defaultdict(dict))

我想要做完全相同的事情(或具有相同行为的事情)。在创建对象之前不断初始化每个级别确实很奇怪。

javascript / typescript上有类似的东西吗?

3 个答案:

答案 0 :(得分:1)

没有内置任何内容,但是您可以使用Proxy来拦截属性访问,并在属性不存在时插入默认值。也许是这样的:

function defaultDict<T>(cb: (k: PropertyKey) => T): { [k: string]: T } {
    return new Proxy({} as any, {
        get(target, p, receiver) {
            if (!(p in target)) {
                target[p] = cb(p);
            }
            return target[p];
        }
    })
}

我不知道回调函数是否关心传入的密钥,但无论哪种方式都没有关系。然后,您可以像这样制作result

const result: IResult = defaultDict(() => ({}));

它实际上只需要有一个defaultDict(),因为设置result[day][match] = ...您实际上只需要定义result[day]。然后,我想这就是您所期望的:

result['2020-09-30']['2020093012344321'] = {
    teams: [
        {
            teamId: '1234',
            teamName: 'Lakers'
        },
        {
            teamId: '4321',
            teamName: 'Miami Heat'
        }
    ],
    winner: {
        teamId: '1234',
        teamName: 'Lakers'
    },
    winnerScore: 117,
    loserScore: 107
};

这没有错误,然后就可以了:

for (let day in result) {
    for (let match in result[day]) {
        console.log(JSON.stringify(result[day][match]))
    }
}
/* {"teams":[{"teamId":"1234","teamName":"Lakers"},{"teamId":"4321","teamName":"Miami Heat"}],
 "winner":{"teamId":"1234","teamName":"Lakers"},"winnerScore":117,"loserScore":107} */

Playground link to code

答案 1 :(得分:0)

不幸的是,不,javascript确实没有任何东西允许一次性设置多个嵌套级别的字典。

答案 2 :(得分:0)

可悲的是,JavaScript无法做到这一点。但是,您可以使用一些依赖项来实现此目的,例如lodash

const _ = require('lodash');

const result: IResult = {};
_.set(result, ['2020-09-30', '2020093012344321'], {} /* replace {} with your value */);