Similar to Flow, TypeScript also provides an immutable ReadonlyArray (introduced in v2.0 that could be used to type GraphQL lists. Would you consider using ReadonlyArray instead of Array? Or a union of both, so I don't have to manually cast all ReadonlyArrays to Arrays to match the QueryVariable type.
One thing to consider is that the Apollo Client update API actually depends on results being mutable. For example, you would make changes to the result of readQuery and write them back with writeQuery.
There is an existing discussion about this in a PR for Flow, but the same reasoning applies to TypeScript, and we probably want a common solution.
I may not understand all the nuances to the readQuery/writeQuery API, but this is only an issue for variables, not for results.
Results should certainly be mutable. When I query apollo, I want mutable results. As @martijnwalraven points out, I may wish to mutate the result, or simply pass it to a function which takes an Array<T> – which implies to typescript that it needs the mutation functions, even if it doesn't actually mutate its arguments. Using a readonly type for results unnecessarily constrains my use of data returned by apollo, so it should continue to use Array, and not ReadonlyArray.
But for the variable types, you'd only use them as a structure I'm about to pass _into_ Apollo. Apollo should let me pass in as a variable any value that matches the constraints. Apollo does not mutate it's variables, so it should allow immutable values to be passed as arguments.
I was just bit by this same issue, when using an immutable set structure implemented as a ReadonlyArray. We were using an array instead of a Set so that values could be used as query variables and results, but the overly restrictive variable type didn't allow it.
Is there something I'm missing?
Making query results immutable would be a huge benefit to apps embracing immutabilty and the OnPush change detection strategy.
How about just adding a feature flag to codegen:generate ?
Something like apollo codegen:generate --immutable and then all generated typescript (or any other language that supports it) interfaces will be readonly.
In Typescript this should add readonly to all properties, and replace all [] (or Array<...>) with ReadonlyArray<...>. Like this:
export interface Foo_bars {
readonly id: string;
readonly name: string | null;
}
export interface Foo {
readonly bars: ReadonlyArray<Foo_bars>;
}
This way the user can decide which solution he/she prefers.
Or you just build your own DeepReadonly typescript interface, which does all that for you. See here: https://github.com/Microsoft/TypeScript/issues/13923
Then you can just take your normal generated typescript interface and use it like this:
const foo: DeepReadonly<Foo> = myInstanceOfFoo;
I am not sure why this issue is closed without any response, but for those who might be looking for a solution, there is an option called --useReadOnlyTypes that can be used with apollo client:codegen --useReadOnlyTypes.
Most helpful comment
I may not understand all the nuances to the
readQuery/writeQueryAPI, but this is only an issue for variables, not for results.Results should certainly be mutable. When I query apollo, I want mutable results. As @martijnwalraven points out, I may wish to mutate the result, or simply pass it to a function which takes an
Array<T>– which implies to typescript that it needs the mutation functions, even if it doesn't actually mutate its arguments. Using a readonly type for results unnecessarily constrains my use of data returned by apollo, so it should continue to useArray, and notReadonlyArray.But for the variable types, you'd only use them as a structure I'm about to pass _into_ Apollo. Apollo should let me pass in as a variable any value that matches the constraints. Apollo does not mutate it's variables, so it should allow immutable values to be passed as arguments.
I was just bit by this same issue, when using an immutable set structure implemented as a ReadonlyArray. We were using an array instead of a Set so that values could be used as query variables and results, but the overly restrictive variable type didn't allow it.
Is there something I'm missing?