So to generalise your point you need a counter for each transition to a different type of opener.
So (([])) needs only 2 counters, not 3.
You could constrain it further if certain types of openers are only valid in certain cases so you could exclude certain types of transitions.
EDIT:
([)] could indeed be handled by just additionally tracking the current open type. (([]]) is a better example, as it shows that to handle deeper nesting you need additional pieces of data that will grow at some rate (at most by the number of opens, possibly lower depending on which types can validly appear within which types)