Searching a nested data structure for 2 attributes
You are correct, this is an inefficient way to do this search. Even if the groupInfo is found in the first iteration of each loop, you still go through (almost) every single element.

First a couple comments on your code:


The return type is lying to me. The function doesn't return BudgetGroupInfo. It returns BudgetGroupInfo | null. The fact that this doesn't complain means that you don't have strictNullChecks on. In my experience, this is the single most helpful feature available. It will let TypeScript tell you about a whole class of errors that it otherwise ignores.
filter.map.forEach is fine if you know only a few elements will be looped over, but if you end up having a lot of data, this will end up taking 3x the time. I don't find it that helpful for readability here, so I'd just pull the checks into the loop function.
TypeScript is generally pretty good about figuring out what variable types are. You don't need to manually type the result of Array#find.


The main trick for optimizing this is to make use of Array#some and change the outer forEach into a find. Here's how I'd write your function:

function getGroupInfo(budCat: string, account: string, budgetGroupInfo: BudgetGroupInfo[]) {
    return budgetGroupInfo.find(group =&gt; {
        return group.bcInfo.some(info =&gt; {
            if (info.name !== budCat) return false;
            return info.bcAccounts.some(acct =&gt; acct.name === account);
        });
    });
}


There are a few subtle differences:


This returns undefined instead of null if there is no result. If this is a problem, it's a straightforward fix.
I removed the return type of the function. TypeScript can infer it easily in this case, and it will still be correctly inferred if you turn on strictNullChecks
If there is multiple matches (I know you said there wouldn't be but...) my version will return the first match, while yours returns the last match.