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

Den*_*nez 12 typescript apollo-server

我正在使用带有打字稿的apollo 服务器,但在我的解析器中获取上下文参数以获取name属性context是字符串时遇到问题。现在它被输入为any,我希望它被输入为string. 我还看到context参数的类型为 any,当我希望它是特定接口时。反正有没有告诉上下文和它的属性我想要它是什么类型而不是它们都被输入为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' 
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

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

context<{ name: string }>() {
  return { 
    name: 'John Doe' 
  }
}
Run Code Online (Sandbox Code Playgroud)

我确实通过明确告诉上下文它需要什么来让它工作,但这种方式似乎有点乏味,因为我必须导入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
      }
    }
  }
  ...
})
Run Code Online (Sandbox Code Playgroud)

pal*_*sey 5

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

generates:
  src/generated/graphql.ts:
    config:
      contextType: "src/types#Context"
Run Code Online (Sandbox Code Playgroud)

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

export interface Context {
  username: string;
}
Run Code Online (Sandbox Code Playgroud)

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


小智 4

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

作为参考,接受此处声明的对象ApolloServer实例或对象数组:https: //github.com/apollographql/apollo-server/blob/a241d34e9275bf6a23cf7aa3ddee57f90de7b364/packages/apollo-server-core/src/types.ts#L90。具有通用类型参数,但默认为任何:https://github.com/ardatan/graphql-tools/blob/8c8d4fc09ddc63c306db16d7386865ac297794bd/packages/utils/src/Interfaces.ts#L298。在您的代码示例中,是组成和实现的特定类型之一:https://github.com/ardatan/graphql-tools/blob/8c8d4fc09ddc63c306db16d7386865ac297794bd/packages/utils/src/Interfaces.ts#L236IResolversIResolversQueryIResolverstest()IFieldResolver

您可以利用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,
  ...
Run Code Online (Sandbox Code Playgroud)