如何在 Apollo Server 中正确键入上下文对象?

How can I correctly type the context object in Apollo Server?

我将 apollo server 与打字稿一起使用,但我无法在我的解析器中获取上下文参数来获取 [=14= 上的 name 属性 ] 是一个字符串。现在输入为 any,我希望输入为 string。我还看到 context 参数是任何类型,当我希望它是一个特定的接口时。无论如何告诉上下文和它的属性我想要它是什么类型而不是它们都被键入为 any?

const server = new ApolloServer({
  typeDefs: gql`
    type Query {
      test: String
    }
  `,
  resolvers: {
    Query: {
      test(parent: any, args: any, context, info: any) {
        context.name // name is typed as "any" when I'd like it to be typed as "string"
      }
    }
  },
  context() {
    return { 
      name: 'John Doe' 
    }
  }
})

我试图做这样的事情,但会引发错误。

context<{ name: string }>() {
  return { 
    name: 'John Doe' 
  }
}

我确实通过明确告诉上下文它需要什么来让它工作,但这种方式似乎有点乏味,因为我必须将 Context 导入每个解析器文件并手动转换。

interface Context {
  name: string
}

const server = new ApolloServer({
  ...
  resolvers: {
    Query: {
      test(parent: any, args: any, context: Context, info: any) {
        context.name // name is typed as "string" here because I used "context: Context" explicitly
      }
    }
  }
  ...
})

默认情况下,您提供给 ApolloServerConfig 对象上的 resolvers 字段对任何类型开放,但您可以使用 TypeScript 进行自己的类型缩小。

作为参考,ApolloServer 接受 IResolvers 对象的实例或数组,如下所示:https://github.com/apollographql/apollo-server/blob/a241d34e9275bf6a23cf7aa3ddee57f90de7b364/packages/apollo-server-core/src/types.ts#L90. IResolvers has generic type parameters, but those default to any: https://github.com/ardatan/graphql-tools/blob/8c8d4fc09ddc63c306db16d7386865ac297794bd/packages/utils/src/Interfaces.ts#L298. In your code sample, Query is one of the specific types that make up IResolvers and test() implements IFieldResolver: https://github.com/ardatan/graphql-tools/blob/8c8d4fc09ddc63c306db16d7386865ac297794bd/packages/utils/src/Interfaces.ts#L236.

您可以利用 IResolvers 具有通用参数这一事实来限制 context 参数的类型。例如,通过在赋值的左侧显式指定类型,您可以告诉编译器在右侧期望什么:

interface Context {
  username: string
}

const myResolvers: IResolvers<any, Context> = {
  Query: {
    test: (parent, args, context) => {
      console.log(context.username) // based on generics TS knows context is supposed to be of type Context
    }
  }
}

new ApolloServer({
  ...
  resolvers: myResolvers,
  ...

如果您graphql-code-generator要生成您的类型,您可以在codegen.yml中配置上下文类型:

generates:
  src/generated/graphql.ts:
    config:
      contextType: "src/types#Context"

然后定义您的上下文类型:

export interface Context {
  username: string;
}

现在,您的解析器方法的 context 参数将被键入 Context,而无需导入类型或进行任何其他更改。