First, in order for the compiler to keep track of the literal types of the elements of GROUPS and not just string, you should use a const assertion when you initialize it:
const GROUPS = ['Objects', 'Things', 'Stuff'] as const;
// const GROUPS: readonly ["Objects", "Things", "Stuff"]
You can see that GROUPS's type is now a readonly tuple consisting of literal types.
Once you do that you can define GroupType as a mapped type over the union of elements of the GROUPS array, by indexing into the type typeof GROUPS (using the typeof type operator) with a number index (since the type you get when accessing GROUPS[n] where n is of type number is a union of the element types):
type GroupType = { [K in typeof GROUPS[number]]: Group }
/* type GroupType = {
Objects: Group;
Things: Group;
Stuff: Group;
} */
You could also write this out like:
type GROUPS = typeof GROUPS[number];
type GroupType = Record<GROUPS, Group>;
/* type GroupType = {
Objects: Group;
Things: Group;
Stuff: Group;
} */
where we give a type named GROUPS to the element types of the GROUPS value, and we use the Record<K, V> utility type instead of the equivalent manually-written mapped type.
Playground link to code