I updated my type-graphql to the beta ^0.18.0-beta.10, because error in the stable version with serverless. now I'm getting another error in the buildSchema function
// resolver.ts
export const resolverArray = [AddressResolver, ProfileResolver];
```js
// schema.ts
import {resolverArray} from '../resolver';
...
const schema = await buildSchema({
resolvers: resolverArray,
authChecker: customAuthChecker,
emitSchemaFile: path.resolve(__dirname, 'schema.gql'),
});
- Error happened only when I compile using tsc:
src/graphql/schema/index.ts:27:5 - error TS2322: Type '(typeof AddressResolver | typeof ProfileResolver )[]' is not assignable to type 'NonEmptyArray
Property '0' is missing in type '(typeof AddressResolver)[]' but required in type 'NonEmptyArray
27 resolvers: resolverArray,
~~~~~
The expected type comes from property 'resolvers' which is declared here on type 'BuildSchemaOptions'
Found 1 error.
- the code works when I create the resolverArray when passing it to the Resolver parameter like:
```js
buildSchema({
resolvers: [AddressResolver, ..etc],
...
*Enviorment *
v0.18 is using NonEmptyArray instead of just [] to prevent passing empty array.
In your case, TS doesn't now that it's not empty array, so the simplest fix is to tell TS compiler that it's a tuple, not a dynamic array:
export const resolverArray = [AddressResolver, ProfileResolver] as const;
In other cases, you can just assert the type if you know what you're doing:
const schema = await buildSchema({
resolvers: resolverArray as NonEmptyArray<Function>,
});
@MichalLytek thanks, it worked after defining it as NonEmptyArray
export const resolverArray = [AddressResolver, ProfileResolver] as NonEmptyArray<Function>;
Can this decision be revisited? It makes it painful to use arrays that aren't array literals and there is a runtime initialization check anyway.
It kind of seems like one of those "neat tricks" that you _can_ do in TS but I'm not sure that we _should_. If other libraries starting doing that kind of thing all over the place it would be a pain to use. Plus, type casts in TypeScript are very generous so I prefer to avoid them where possible (they will happily cast between incompatible types). Just my ten cents though.
there is a runtime initialization check anyway
But there shouldn't as we want to have type safety, not runtime failures 馃槈
If you create the array directly in the options it's not a problem.
If you create multiple arrays in modules and then import them and merge, just use as const syntax while creating each of them to tell TS it's gonna be a constant tuple, not a mutable array.
If you create your array dynamically based on some options, use a type guard that will check the length of the array and tell the compiler it's gonna be non empty array:
function isNotEmptyArray<T>(array: T[]): array is NonEmptyArray<T> {
return array.length > 0 && array[0] !== undefined;
}
I think it is worth to note that using as const makes the exported array readonly, which results in The type 'readonly [typeof AResolver, typeof AnotherResolver, ...]' is 'readonly' and cannot be assigned to the mutable type 'NonEmptyArray<string>'.ts(4104).
@EirikFA
Thanks for reporting this 馃檹
Looks like it's the new TS behavior, so I gonna change the type to:
export type NonEmptyArray<TItem> = readonly [TItem, ...TItem[]];
I've added a more explicit info in docs how to do that:
https://typegraphql.com/docs/next/bootstrap.html#create-executable-schema
Most helpful comment
v0.18 is using
NonEmptyArrayinstead of just[]to prevent passing empty array.In your case, TS doesn't now that it's not empty array, so the simplest fix is to tell TS compiler that it's a tuple, not a dynamic array:
In other cases, you can just assert the type if you know what you're doing: