This course is no longer maintained and may be out-of-date. While it remains available for reference, its content may not reflect the latest updates, best practices, or supported features.
Mapping Types
Let's type safe the useQuery
so that we parse the right result object state, which includes loading
, error
and data
.
The auto-generated type definitions are available at src/generated/graphql.tsx
file. Let's import GetMyTodosQuery
relevant for this component.
import React, { Fragment, useState } from "react";import { gql, useMutation } from "@apollo/client"import TodoItem from "./TodoItem";import TodoFilters from "./TodoFilters";+ import {+ GetMyTodosQuery,+ } from '../../generated/graphql';
Now let's add this to useQuery
:
const TodoPrivateList = () => {const [filter, setFilter] = useState<string>("all");- const { loading, error, data } = useQuery(GET_MY_TODOS);+ const { loading, error, data } = useQuery<GetMyTodosQuery>(GET_MY_TODOS);const filterResults = (filter: string): void => {setFilter(filter);};
We also have Todo
type manually defined in the app boilerplate before the GraphQL integration. Let's import Todos
type definition from the generated file.
import {- GetMyTodosQuery+ GetMyTodosQuery,+ Todos} from '../../generated/graphql';
Let's update the parts of code where the Todo
type is being used.
let filteredTodos = data.todos;if (filter === "active") {- filteredTodos = data.todos.filter((todo: Todo) => todo.is_completed !== true);+ filteredTodos = data.todos.filter((todo: Pick<Todos, "id" | "title" | "is_completed">) => todo.is_completed !== true);} else if (filter === "completed") {- filteredTodos = data.todos.filter((todo: Todo) => todo.is_completed === true);+ filteredTodos = data.todos.filter((todo: Pick<Todos, "id" | "title" | "is_completed">) => todo.is_completed === true);}- const todoList = filteredTodos.map((todo: Todo, index: number) => (+ const todoList = filteredTodos.map((todo: Pick<Todos, "id" | "title" | "is_completed">, index: number) => (<TodoItemkey={'item'+index}index={index}todo={todo}/>));
We are using Pick<Todos, "id" | "title" | "is_completed">
, instead of <Todos>
to handle properties that are not used in the UI.
And now with updated todos, let's remove the manually declared type definition for todo.
- type Todo = {- id: number,- title: string,- is_completed: boolean- };const TodoPrivateList = () => {const [filter, setFilter] = useState<string>("all");const { loading, error, data } = useQuery<GetMyTodosQuery>(GET_MY_TODOS);
Since we have updated the todo type here, the same needs to be reflected in TodoItem
component as well.
Open src/components/Todo/TodoItem.tsx
import * as React from 'react';+ import { Todos } from '../../generated/graphql';- export type TodoItem = {- id: number,- title: string,- is_completed: boolean- };interface TodoItemType {index: number,- todo: TodoItem+ todo: Pick<Todos, "id" | "title" | "is_completed">;};
Again let's update the TodoFilters
component as well which imports the TodoItem
type definition.
import * as React from 'react';- import { TodoItem } from './TodoItem';+ import { GetMyTodosQuery } from '../../generated/graphql';interface filterResults {(filter: string): void}interface TodoFiltersArgs {- todos: TodoItem[],+ todos: GetMyTodosQuery["todos"],currentFilter: string,filterResultsFn: filterResults,clearCompletedFn: VoidFunction}
Note that here we are importing GetMyTodosQuery
and getting the type of todos
property using GetMyTodosQuery["todos"]
. Here todos
is an array where as previously we were defining type for a single todo.
Build apps and APIs 10x faster
Built-in authorization and caching
8x more performant than hand-rolled APIs

