You either have to make these disparate types implement the same interface, make your resolvers return unions, or create a custom scalar to hold the dynamic data.
The cleanest approach is the first one: if your resulting objects can be of a limited number of types, define the types so that they implement the same interface, and type your resolvers by the interface. This allows the client to conditionally select sub-fields based on the actual type, and you maintain type safety.
The second approach has similar limitations: you need to know the possible types ahead of time, but they do not have to implement the same interface. It is preferable when the possible values are unrelated to each other and have either/or semantics, like success/failure.
The custom scalar approach is the only one in which you do not need to know the possible types of the result, i.e. the structure of the result can be completely dynamic. Here's an implementation of that approach, known as JSON scalar (i.e. cram any JSON-serializable structure into a scalar value). The big downside of this approach is that it makes sub-selection impossible, as the entire value becomes one big scalar (even though it's a complex object).
Since the question is asking about an array of objects of unknown types, I'll point out that you can, of course, have a list of all the options above.
Examples:
#Interface for any search result
interface SearchResult {
title: String!
url: String!
}
#A specific kind of search result
type Book implements SearchResult {
title: String!
url: String!
author: Author!
isbn: String!
}
type Article implements SearchResult {
title: String!
url: String!
categories: [Category]!
}
type Query {
#Search can return a mix of Books and Articles
search(keyword: String!): [SearchResult!]
}
Or
#No interface this time
type Book {
name: String! #No common fields with Article
author: Author!
publisher: Publisher!
}
type Article {
title: String!
url: String!
categories: [Category]!
}
union SearchResult = Book | Article
type Query {
#Search can return a mix of Books and Articles
search(keyword: String!): [SearchResult!]
}
Or
scalar JSON
type Query {
#Search can return anything at all... All bets are off
search(keyword: String!): [JSON!]
}