It's possible to do this, but the solution will require you to type factories as read-only, or the type will simply not contain enough information.
const factories = [() => new Dog(), () => new Cat()] as const;
If you declare a type for such factories (which aren't really about animals anymore, but let's stick with it)
type AnimalFactory<T> = () => T
you can create a mapped type that takes a tuple of AnimalFactory's and yields a tuple of the respective animal types:
type FactoryAnimals<T extends AnimalFactory<unknown>[]> =
{[K in keyof T]: T[K] extends AnimalFactory<infer A> ? A : never}
Now you can use AnimalFactory for the return type of createAnimals:
const createAnimals = <T extends AnimalFactory<unknown>[]>
(factories: readonly [...T]) => factories.map(f => f()) as FactoryAnimals<T>;
Unfortunately the as FactoryAnimals<T> assertion is necessary since TypeScript can't infer that doing a map on the tuple yields the mapped type. The readonly [...T] bit is to avoid having a read-only T, which would cause a read-only return type and require an extra assertion.
If you call createAnimals on the factories it produces a tuple of the desired type:
const animals = createAnimals(factories);
// type: [Dog, Cat]
// ❌ should fail !
animals[0].meow(); // Error: Property 'meow' does not exist on type 'Dog'.
And if you call it with an explicit array instead of a variable, you can leave out the as const, since the [...T] type causes factories to be considered a tuple:
const animals = createAnimals([() => new Dog(), () => new Cat()]);
// type: [Dog, Cat]
TypeScript playground
AnimalFactory? A type you already have? Or something you tried to use to make this work?