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

20
我正在使用typescript的apollo server,但是在我的解析器内部获取上下文参数时遇到了麻烦,因为context上的name属性被识别为any类型,而不是string类型。我希望它的类型能够被定义为string。同时,我也发现context参数的类型为any,而我想要它成为一个特定接口的类型。是否有办法告诉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
      }
    }
  }
  ...
})
2个回答

5
如果您正在使用graphql-code-generator生成类型,则可以在codegen.yml中配置上下文类型:
generates:
  src/generated/graphql.ts:
    config:
      contextType: "src/types#Context"

然后定义您的上下文类型:
export interface Context {
  username: string;
}

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

当我初始化代码生成器时,它创建了一个TypeScript配置文件。如何使用该文件设置上下文类型? - Gabe

4
默认情况下,你提供给 ApolloServerConfig 对象中的 resolvers 字段对于任何类型都是开放的,但是你可以使用 TypeScript 来自己进行类型缩小。
作为参考,ApolloServer 接受一个或一组声明为此处所示的 IResolvers 对象实例: https://github.com/apollographql/apollo-server/blob/a241d34e9275bf6a23cf7aa3ddee57f90de7b364/packages/apollo-server-core/src/types.ts#L90 IResolvers 有通用类型参数,但这些默认为 any: https://github.com/ardatan/graphql-tools/blob/8c8d4fc09ddc63c306db16d7386865ac297794bd/packages/utils/src/Interfaces.ts#L298 。 在你的代码示例中, Query 是构成 IResolvers 的特定类型之一,而 test() 实现了 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,
  ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接