Table of Contents

Overview

Typescript is a superset of Javascript which uses static typing, classes, interfaces and is hence called Object Oriented programming language (OOP). Many developers widely use it to minimize errors and for type checking in applications. Adding a strict type makes it a more self-expressive code. Due to the strict behavior, sometimes developers find it difficult to work with typescript in their project.

Typescript code can be run on any browser, device, or operating system. Since typescript is a superset of Javascript, it compiles into Javascript, and every valid Javascript is a valid Typescript. Typescript detects bugs at the compile-time, so the chances of getting errors reduce at the runtime. Typescript has a disadvantage over Javascript in that it takes time to complete the code.

In this tutorial, we will learn about react native app with typescript and see how can we build a basic Quiz application.

Create React Native App

Initially, create a react native app using the below command.

Copy Text
react-native init QuizApp
cd QuizApp

Install Dependencies

Use the below command to install the dependencies.

Copy Text
npm install typescript @types/react @types/react-native 
@types/react-test-renderer @types/jest

Let’s see the purpose of the installed typescript libraries.

  • typescript: To install typescript
  • @types/react: To install react types for typescript
  • @types/react-native: To install React Native types for typescript
  • @types/react-test-renderer: To install types for test-renderer for typescript
  • @types/jest: To install types for jest testing for typescript

We will require Axios for API calls and the library required for the elements used in code. Run the below command for the same.

Copy Text
npm install axios react-native-elements

TypeScript Configuration

We need to configure Typescript for react-native to work. Create a config file named tsconfig.json using the tsc command.

Copy Text
tsc --init

Note– To use the tsc command, you need to have typescript installed globally.

In order to build your react native app with typescript, change App.js to App.tsx.

Create Components

Let’s get started with creating components for our application. Our basic Quiz application will consist of the following components-

  • Screen
  • ➡ Quiz.tsx

  • Components
  • ➡ Headers.tsx
    ➡ Questions.tsx
    ➡ Answers.tsx
    ➡ Buttons.tsx

  • API Call

Now, we will go through each component files step by step and look into the code.

// Headers.tsx

Copy Text
import React, {FC} from 'react';
import {SafeAreaView, StyleSheet, Text, StatusBar} from 'react-native';
 
interface Header {
 title: string;
}
const HeaderClass: FC<Header> = props => {
 return (
   <SafeAreaView>
     <StatusBar backgroundColor="white" />
     <Text style={styles.textstyle}>{props.title}</Text>
   </SafeAreaView>
 );
};
 
const styles = StyleSheet.create({
 textstyle: {
   textAlign: 'center',
   fontSize: 18,
 },
});
 
export default HeaderClass;

Explanation:

Copy Text
interface Header {
 title: string,
}
const HeaderClass: FC<Header>=(props) => {/*content*/}

In typescript, we can define what to take and how to take in the component. Here, we have declared an interface named Header, which defines a structure for the props object to access the component. For that, define propsTo, ‘title’ with a specific type ‘string.’

Here comes the benefit- it gives us some validation when we use this component.

Moreover, we have react native code which shows the text as header title with style defined to it.

// Buttons.tsx

Copy Text
import React, {FC} from 'react';
import {useEffect} from 'react';
import {SafeAreaView, StyleSheet, Text, TouchableOpacity} from 'react-native';
 
interface Title {
 key: number;
 answer: string;
 onPress: () => void;
 correct: boolean;
 disabled: boolean;
}
 
const Buttons: FC<Title> = props => {
 useEffect(() => {}, []);
 return (
   <SafeAreaView>
     <TouchableOpacity
       style={{
         backgroundColor: !props.disabled ? '#F5F5DC' : '#F5DEB3',
         width: '80%',
         elevation: 5,
         justifyContent: 'center',
         alignContent: 'center',
         marginLeft: 27,
         height: 38,
         marginTop: 10,
       }}
       onPress={() => {
         props.onPress();
       }}>
       <Text
         style={[
           styles.textstyle,
           {color: props.correct ? 'brown' : 'black'},
         ]}>
         {props.answer}
       </Text>
     </TouchableOpacity>
   </SafeAreaView>
 );
};
 
const styles = StyleSheet.create({
 textstyle: {
   textAlign: 'left',
   fontSize: 17,
   marginLeft: 8,
 },
});
 
export default Buttons;

In the file Buttons.tsx, we have an interface named Title which holds the structure for props. It changes style according to the correct answer on pressing the button and disables other buttons according to passed props from the parent class.

// Answers.tsx

Copy Text
import React, {FC} from 'react';
import {SafeAreaView, StyleSheet, View} from 'react-native';
import Buttons from '../components/Buttons';
import {AnswerObject} from '../screens/Quiz';
 
interface Answers {
 useranswer: AnswerObject | undefined;
 answers: string[];
 setcorrectanswer: any;
 checkanswer: () => void;
}
 
const Answers: FC<Answers> = props => {
 return (
   <SafeAreaView>
     <View style={{marginTop: 10, paddingHorizontal: 20}}>
       {props.answers.map((answer, key) => {
         return (
           <View key={answer}>
             <Buttons
               {...{key, answer}}
               correct={props.useranswer?.correctanswer === answer}
               disabled={props.useranswer ? true : false}
               onPress={() => {
                 (props.setcorrectanswer.current = answer),
                   props.checkanswer();
               }}
             />
           </View>
         );
       })}
     </View>
   </SafeAreaView>
 );
};
 
const styles = StyleSheet.create({
 questioncontainer: {
   flexDirection: 'row',
   alignItems: 'center',
   backgroundColor: 'white',
   marginTop: 10,
   paddingRight: 16,
 },
 
 textstyle: {padding: 15, fontSize: 15, color: 'blue'},
});
 
export default Answers;

In this file, we have an interface named Answers which defines an answer, useranswer, having another type interface AnswerObject (used in the class Quiz), correctanswer, checkanswer function. This file shows the multiple options below the question to choose from the prop of the child class.

// Question.tsx

Copy Text
import React, {FC} from 'react';
import {SafeAreaView, StyleSheet, Text, View} from 'react-native';
 
interface Question {
 QuestionNo: number;
 Question: string;
}
 
const Questions: FC<Question> = props => {
 return (
   <SafeAreaView>
     <View style={styles.questioncontainer}>
       <Text style={styles.textstyle}>{props.QuestionNo}</Text>
       <Text
         style={{
           fontSize: 15,
           color: 'black',
           textAlign: 'left',
           marginRight: 7,
         }}>
         {props.Question}
       </Text>
     </View>
   </SafeAreaView>
 );
};
 
const styles = StyleSheet.create({
 questioncontainer: {
   flexDirection: 'row',
   alignItems: 'center',
   backgroundColor: 'white',
   marginTop: 10,
   paddingRight: 16,
 },
 
 textstyle: {padding: 15, fontSize: 15, color: 'blue'},
});
 
export default Questions;

In this file we have an interface named Question which defines props for QuestionNo and Question.

// Quiz.tsx

Copy Text
import React, {FC, useEffect, useRef, useState} from 'react';
import {
 StyleSheet,
 Text,
 View,
 TouchableOpacity,
 ActivityIndicator,
} from 'react-native';
import {getquestiojns, Question} from '../utils/api';
import Questions from '../components/Question';
import Answers from '../components/Answers';
import {Icon} from 'react-native-elements';
 
export type AnswerObject = {
 question: string;
 answer: string;
 correct: boolean;
 correctanswer: string;
};
 
const Quiz: FC = props => {
 const [loader, setloader] = useState(false);
 const [question, setquestion] = useState<Question[]>([]);
 const [useranswers, setuseranswers] = useState<AnswerObject[]>([]);
 const [score, setscore] = useState(0);
 const [number, setnumber] = useState(0);
 const [totalquestion] = useState(10);
 const [gameover, setgameover] = useState(true);
 const setcorrectanswer = useRef(null);
 const [correcta, setcorrecta] = useState('');
 
 useEffect(() => {
   startQuiz();
 }, []);
 const startQuiz = async () => {
   setnumber(0);
   setloader(true);
   setgameover(false);
   const newquestions = await getquestiojns();
   console.log(newquestions);
   setquestion(newquestions);
   setscore(0);
   setuseranswers([]);
   setloader(false);
 };
 const nextQuestion = () => {
   const nextq = number + 1;
   if (nextq == totalquestion) {
     setgameover(true);
   } else {
     setnumber(nextq);
   }
 };
 const checkanswer = () => {
   if (!gameover) {
     const answer = setcorrectanswer.current;
 
     const correcta = question[number].correct_answer === answer;
 
     if (correcta) setscore(prev => prev + 1);
 
     const answerobject = {
       question: question[number].question,
       answer,
       correcta,
       correctanswer: question[number].correct_answer,
     };
 
     setuseranswers(prev => [...prev, answerobject]);
     setTimeout(() => {
       nextQuestion();
     }, 1000);
   }
 };
 
 return (
   <View style={{flex: 1}}>
     {!loader ? (
       <View>
         <View style={styles.container}>
           <Text style={styles.textstyle}>Questions</Text>
           <Text style={styles.textstyle}>
             {number + 1}/{totalquestion}
           </Text>
         </View>
         <View style={{marginLeft: 20}}>
           <Text style={styles.textstyle}>Score : {score}</Text>
         </View>
         {question.length > 0 ? (
           <>
             <Questions
               QuestionNo={number + 1}
               Question={question[number].question}
             />
             <Answers
               answers={question[number].answers}
               {...{setcorrectanswer, checkanswer}}
               useranswer={useranswers ? useranswers[number] : undefined}
             />
           </>
         ) : null}
       </View>
     ) : (
       <ActivityIndicator
         style={{justifyContent: 'center', top: 200}}
         size={50}
         color="black"
       />
     )}
 
     <View>
       {!gameover && !loader && number != totalquestion - 1 ? (
         <TouchableOpacity onPress={() => nextQuestion()}>
           <Icon
             name="arrowright"
             size={40}
             color="black"
             type="antdesign"
             style={{left: 130, margin: 20}}
           />
         </TouchableOpacity>
       ) : number == totalquestion - 1 ? (
         <TouchableOpacity onPress={() => startQuiz()}>
           <Icon
             name="controller-play"
             size={40}
             color="black"
             type="entypo"
             style={{left: 130, margin: 20}}
           />
         </TouchableOpacity>
       ) : null}
     </View>
   </View>
 );
};
 
const styles = StyleSheet.create({
 container: {
   flexDirection: 'row',
   justifyContent: 'space-between',
   marginTop: 70,
   backgroundColor: 'white',
 },
 textstyle: {padding: 15, fontSize: 15, color: 'blue'},
 bottomview: {
   padding: 13,
   backgroundColor: 'blue',
   borderRadius: 300,
   width: 70,
   height: 70,
   position: 'absolute',
   right: 20,
   top: 550,
 },
 questioncontainer: {
   flexDirection: 'row',
   alignItems: 'center',
   backgroundColor: 'white',
   marginTop: 10,
   paddingRight: 16,
 },
 iconstyle: {
   backgroundColor: 'blue',
   borderRadius: 50,
   width: 70,
   height: 70,
   margin: 5,
   top: 100,
   left: 260,
 },
});
 
export default Quiz;

This is the main screen which is shown on loading. When the screen gets rendered, it sets all the states to the initial phases and calls API to set questions and options to display. When API returns data, the Question and Answers classes are called to render the items with the help of props.

The answers class uses a function called checkanswer, which checks the current reference of the selected answer and checks it with the API’s correct answer. If they match, then the score gets increased by one and proceeds to the next question.

Want to leverage the advanced features of the New React Native Architecture?
Hire React Native developer from us who will bring the best of React ecosystem to outshine your cross-platform mobile application at the top

// src/utils/api.tsx

Copy Text
import axios from 'axios';
 
export const _ = (array: any[]) => [...array].sort(() => Math.random() - 0.7);
 
export type Question = {
 category: string;
 incorrect_answers: string[];
 correct_answer: string;
 difficulty: string;
 question: string;
 type: string;
};
export const getquestiojns = async () => {
 const endpoint = 'https://opentdb.com/api.php?amount=10&category=9';
 const promise = await axios.get(endpoint);
 return promise.data.results.map((question: Question) => ({
   ...question,
   answers: _([...question.incorrect_answers, question.correct_answer]),
 }));
};

In this file, we have an interface named Question, which has a structure to use as props to return the desired options in this Quiz App. It uses the Axios library to fetch details from the API. It returns the result from API, which has questions and answers based on multiple options.

Github Repository: React Native App with Typescript

You can visit here – Github Repository and play around with code or follow the steps mentioned above for developing a React Native app with Typescript.

Conclusion

So, this was all about building a basic React Native App with Typescript. A simple Quiz application flow to better understand how typescript works in react native. I hope your purpose for landing on this tutorial has been fulfilled. For more such tutorials, feel free to visit the React Native tutorials page. We have step-by-step guidelines comprising basic and advanced React Native knowledge; we also provide source code to explore on your own.

Want to Know Why and When to Use React Native App With TypeScript?

Connect Now

Build Your Agile Team

Hire Skilled Developer From Us

Subscribe for
weekly updates

newsletter

What Makes Bacancy Stand Out?

  • Technical Subject Matter Experts
  • 2500+ Projects Completed
  • 90% Client Retention Ratio
  • 12+ Years of Experience

Our developers primarily focus on navigating client's requirements with precision. Besides, we develop and innovate to deliver only the best solutions to our clients.

get in touch
[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.

How Can We Help You?