En este tutorial, explicaré qué son TypeScript y GraphQL y los beneficios de usarlos.
¿Qué es TypeScript?
TypeScript es un superconjunto de JavaScript que se compila en JavaScript para la producción. Es como JavaScript, pero con poderes: escribe poderes.
TypeScript lo ayuda a crear aplicaciones escritas que lo ayudan a evitar errores estáticos en esas aplicaciones y crear código predecible.
Sin TypeScript, una función declarada para tomar un argumento de tipo cadena podría recibir un argumento de tipo numérico durante la ejecución y podría recibir un error de tiempo de ejecución. Esto puede ser perjudicial para el código de producción.
Con TypeScript, esta función dará como resultado un error en tiempo de compilación a menos que se pase el tipo apropiado.
TypeScript puede manejar múltiples tipos primitivos. También puede garantizar que se escriban los objetos estructurados correctos y esperados. Esto significa que una propiedad de objeto faltante también puede causar un error.
TypeScript nos ayuda a crear un código JavaScript más predecible durante el desarrollo a través de la verificación de tipos. También está integrado en editores como VSCode, lo que facilita la detección de errores de tipeo al escribir código.
TypeScript requiere un paso adicional de compilación en JavaScript para su uso. Si bien algunas bibliotecas como React hacen esto internamente por usted, es posible que deba configurarlo usted mismo si está construyendo sin tales herramientas. Pero yo diría que vale la pena.
¿Qué es GraphQL?
GraphQL es otro método para la gestión de API. Es una alternativa a la API Rest que te permite solicitar «solo los datos que necesitas». Esto ayuda a reducir la cantidad de datos que el servidor debe enviar al cliente.
Por ejemplo, con una API Rest, un punto final puede devolver datos de todos los usuarios cuando solo se necesitan el correo electrónico y el número de teléfono en ese punto. Esto se llama «obtención excesiva». Con GraphQL, el cliente puede solicitar esos datos específicos.
GraphQL también incluye definiciones de tipo, que existen en objetos de esquema. GraphQL utiliza objetos Schema para saber qué propiedades se pueden consultar y, en la práctica, el tipo de consultas que se aceptan. También arroja un error cuando se ejecuta una consulta no aceptada.
Sin embargo, estas definiciones de tipo están limitadas a objetos de esquema. No le dan tipeo estático general en su aplicación. Y es por eso que TypeScript es una excelente adición, como veremos en el resto de este artículo.
Ventajas de usar TypeScript y GraphQL
El uso de TypeScript y GraphQL garantiza que exista escritura estática en toda la aplicación.
Sin TypeScript, aún puede crear tipos de consulta con GraphQL. Pero hay un límite para esto.
Los tipos de GraphQL solo existen en el esquema de GraphQL. Él buildSchema
La función de biblioteca GraphQL se utiliza para crear un objeto de esquema:
const schema = buildSchema(`
type Query {
name(firstname: String!, lastname: String!): String
}
`)
Hemos creado el objeto de esquema y ahora necesitamos un solucionador:
const root = {
name: variables => {
return `My name is ${firstname} ${lastname}!`
},
}
Consultar con variables escritas incorrectamente en un área de juegos de GraphQL da como resultado errores:

Pero los solucionadores desconocen la definición de tipo en el objeto de esquema. Como puede ver, el solucionador es una función JavaScript normal. Esto significa que no obtenemos escritura estática en el solucionador.
Por ejemplo, suponga que le da al solucionador los tipos de argumento incorrectos o devuelve un tipo diferente al solucionador que el esquema no esperaba. Podríamos introducir errores en nuestro código sin saberlo.
Y es por eso que TypeScript es beneficioso. Con TypeScript, tenemos definiciones de tipos en el objeto de esquema y los solucionadores, sincronizando ambos y haciendo que nuestro código sea mucho más predecible.
Cómo usar TypeScript y GraphQL
En esta sección, usaremos TypeScript y GraphQL para crear una API GraphQL simple en un servidor Express.
Paso 1: Crear una carpeta de proyecto
Puedes ponerle el nombre que quieras, pero usaremos el graphql-ts-example
carpeta para este tutorial:
mkdir graphql-ts-example
cd graphql-ts-example
npm init -y
Paso 2: instala las dependencias
Usaremos las siguientes dependencias para este tutorial:
- gráficoql: la biblioteca de JavaScript para GraphQL
- para expresar: un framework web para Node que nos permite crear APIs y un servidor back-end
- express-graphql: para crear un servidor GraphQL para API
- nodo ts: para ejecutar código TypeScript en Node
- mecanografiado: para compilar código TypeScript en JavaScript
- @ tipos / espresso: para usar Express en TypeScript
- nodomon: para reiniciar el servidor cuando se realizan cambios
En tu terminal, ejecuta:
npm install graphql express express-graphql
npm install -D nodemon ts-node @types/express typescript
Para probar nuestra API, utilizaremos el área de juegos de GraphQL proporcionada por express-graphql.
Paso 3: configurando nuestros scripts
En package.json
actualizar el scripts
objetar esto:
"scripts": {
"start": "nodemon --exec ts-node src/index.ts",
}
Además, agregue un archivo de configuración para TypeScript, tsconfig.json
:
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"jsx": "preserve",
"strict": true,
"esModuleInterop": true,
"lib": ["es2018", "esnext.asynciterable"]
},
"exclude": ["node_modules"]
}
Con esto, podemos ejecutar nuestro servidor con npm start
.
Paso 4: escribe el código
Crearemos un servidor Express con una API GraphQL que nos permitirá recuperar usuarios, crear un usuario y actualizar los datos de un usuario.
Cree un nuevo directorio llamado «src» y agregue el archivo index.ts
archivos en él. Tenemos nuestras importaciones en el archivo de la siguiente manera:
import { buildSchema } from "graphql"
import express from "express"
import { graphqlHTTP } from "express-graphql"
Así que necesitamos nuestra lista de usuarios. Idealmente, esto debería provenir de una base de datos, pero lo codificaremos aquí:
const users = [
{ id: 1, name: "John Doe", email: "johndoe@gmail.com" },
{ id: 2, name: "Jane Doe", email: "janedoe@gmail.com" },
{ id: 3, name: "Mike Doe", email: "mikedoe@gmail.com" },
]
A continuación, construyamos el esquema de GraphQL:
const schema = buildSchema(`
input UserInput {
email: String!
name: String!
}
type User {
id: Int!
name: String!
email: String!
}
type Mutation {
createUser(input: UserInput): User
updateUser(id: Int!, input: UserInput): User
}
type Query {
getUser(id: String): User
getUsers: [User]
}
`)
A partir de nuestro esquema, hemos definido:
- una entrada de usuario con dos propiedades obligatorias, que se requiere al crear un usuario
- un tipo de usuario con tres propiedades requeridas
- una mutación de GraphQL en la que creamos usuarios y actualizamos usuarios
- y una consulta GraphQL para obtener un usuario en particular o todos los usuarios.
Ahora, necesitamos definir nuestros tipos de TypeScript para escritura estática:
type User = {
id: number
name: string
email: string
}
type UserInput = Pick<User, "email" | "name">
A continuación, nuestros solucionadores:
const getUser = (args: { id: number }): User | undefined =>
users.find(u => u.id === args.id)
const getUsers = (): User[] => users
const createUser = (args: { input: UserInput }): User => {
const user = {
id: users.length + 1,
...args.input,
}
users.push(user)
return user
}
const updateUser = (args: { user: User }): User => {
const index = users.findIndex(u => u.id === args.user.id)
const targetUser = users[index]
if (targetUser) users[index] = args.user
return targetUser
}
const root = {
getUser,
getUsers,
createUser,
updateUser,
}
Y finalmente, nuestra ruta Express y del servidor:
const app = express()
app.use(
"/graphql",
graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
})
)
const PORT = 8000
app.listen(PORT)
console.log(`Running a GraphQL API server at http://localhost:${PORT}/graphql`)
Con lo que tenemos arriba, nuestros solucionadores se escriben siguiendo la definición del esquema. De esta forma, nuestros solucionadores están sincronizados. ARRIBA localhost:4000/graphql
podemos ver el patio de recreo de GraphQL:

Si bien podemos ver cuán beneficioso es TypeScript, tampoco podemos negar la molestia de escribir definiciones de tipo después de crear un objeto de esquema.
Esta base de código es pequeña, por lo que puede ser más simple, pero imagina algo grande, con muchos solucionadores y teniendo que crear definiciones de tipo para cada uno 😩
Necesitamos una mejor manera de hacer esto. Necesitamos algo que nos permita crear definiciones de tipo en un solo lugar, como fuente principal de verdad, y luego usarlas en nuestros solucionadores y objetos de esquema.
Cómo usar TypeGraphQL para mejorar su GraphQL escrito
El objetivo de Escriba GraphQL es simplificar la escritura estática en sus solucionadores y crear sus esquemas desde un solo lugar.
Viene con su propia sintaxis, que es otro proceso de aprendizaje. Pero no es tan empinado, es un paso en la dirección correcta.
Mejoramos nuestra base de código usando TypeGraphQL.
Necesitaríamos un par de dependencias:
- validador de clase: Permite el uso de decoradores para validación
- tipo-graphql: la propia biblioteca TypeGraphQL, que le permite crear esquemas y solucionadores con TypeSCript, utilizando clases y decoradores
- reflejar los metadatos: para la reflexión en tiempo de ejecución de los tipos
En tu terminal, ejecuta:
npm install class-validator type-graphql reflect-metadata
En tus tsconfig.json
agregue lo siguiente a compilerOptions
objeto:
"compilerOptions": {
// ...
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
}
Estos son importantes para que TypeScript no se queje del uso de decoradores. Todavía estoy en modo experimental.
Ahora, actualicemos nuestra base de código usando TypeGraphQL. Cree un nuevo directorio llamado «usuarios». En él tendremos el esquema y los solucionadores.
Cree un nuevo archivo en «usuarios» llamado «users.schema.ts»:
// users.schema.ts
import { Field, ObjectType, InputType } from "type-graphql"
@ObjectType()
export class User {
@Field()
id!: number
@Field()
name!: string
@Field()
email!: string
}
@InputType()
export class UserInput implements Pick<User, "name" | "email"> {
@Field()
name!: string
@Field()
email!: string
}
Primero, tenemos la User
clase, que está decorada con el ObjectType
decorador. Esto le dice a GraphQL que esta clase es un tipo de GraphQL. En GraphQL, esto se interpreta como:
buildSchema(`
type User {
id: Int!
name: String!
email: String!
}
input UserInput {
name: String!
email: String!
}
`)
A continuación, nuestros solucionadores. Crear un users.resolvers.ts
archivo en el directorio «usuarios»:
// users.resolvers.ts
import { Query, Resolver, Mutation, Arg } from "type-graphql"
import { UserInput, User } from "./users.schema"
@Resolver(() => User)
export class UsersResolver {
private users: User[] = [
{ id: 1, name: "John Doe", email: "johndoe@gmail.com" },
{ id: 2, name: "Jane Doe", email: "janedoe@gmail.com" },
{ id: 3, name: "Mike Doe", email: "mikedoe@gmail.com" },
]
@Query(() => [User])
async getUsers(): Promise<User[]> {
return this.users
}
@Query(() => User)
async getUser(@Arg("id") id: number): Promise<User | undefined> {
const user = this.users.find(u => u.id === id)
return user
}
@Mutation(() => User)
async createUser(@Arg("input") input: UserInput): Promise<User> {
const user = {
id: this.users.length + 1,
...input,
}
this.users.push(user)
return user
}
@Mutation(() => User)
async updateUser(
@Arg("id") id: number,
@Arg("input") input: UserInput
): Promise<User> {
const user = this.users.find(u => u.id === id)
if (!user) {
throw new Error("User not found")
}
const updatedUser = {
...user,
...input,
}
this.users = this.users.map(u => (u.id === id ? updatedUser : u))
return updatedUser
}
}
Hay algunos decoradores a tener en cuenta aquí:
- Ahí está el
Resolver
decorador, que decora la clase como un objeto con muchos métodos de resolución de consulta y mutación. Lo bueno aquí es que estamos definiendo las consultas y las mutaciones y los métodos de resolución en la misma clase. - Ahí está el
Query
decorador, que le dice a GraphQL que se trata de una consulta y su método de resolución - Ahí está el
Mutation
decorador, que le dice a GraphQL que es una mutación y su método de resolución - Ahí está el
Arg
decorador, que le dice a GraphQL que este argumento es un argumento de GraphQL para el solucionador.
Como notará, sin crear una definición de tipo para el User
objeto, podríamos simplemente usar la clase exportada del archivo de esquema.
El código anterior se interpretará en GraphQL como:
buildSchema(`
type Query {
getUsers: [User]
getUser(id: Int!): User
}
type Mutation {
createUser(input: UserInput): User
updateUser(id: Int!, input: UserInput): User
}
`)
// resolvers
volver adentro src/index.ts
así es como se ve el código:
import "reflect-metadata"
import { buildSchema } from "type-graphql"
import express from "express"
import { graphqlHTTP } from "express-graphql"
import { UsersResolver } from "./users/users.resolver"
async function main() {
const schema = await buildSchema({
resolvers: [UsersResolver],
emitSchemaFile: true,
})
const app = express()
app.use(
"/graphql",
graphqlHTTP({
schema: schema,
graphiql: true,
})
)
app.listen(8000)
console.log("Running a GraphQL API server at http://localhost:8000/graphql")
}
main()
Él buildSchema
la función se deriva de la type-graphql
biblioteca esta vez. De vuelta en el área de juegos de GraphQL, nuestras consultas funcionan como se esperaba:

Aquí está el repositorio de GitHub para este proyecto: Graphql-ejemplo-mecanografiado
Conclusión
En este artículo, hemos aprendido qué son GraphQL y TypeScript y hemos visto las limitaciones de usar GraphQL sin TypeScript.
También hemos visto una excelente manera de usar GraphQL y TypeScript juntos: TypeGraphQL.
Si lo encuentra útil, por favor compártalo con otros 🙂
Deja una respuesta