Lesson 75 of 60 – TypeScript with AsyncStorage
100%

TypeScript with AsyncStorage

React Native applications often need to store small amounts of data locally on the device. AsyncStorage can be used for values such as login preferences, settings, tokens, and other non-sensitive application data.

TypeScript helps us define the types of data we store and retrieve, making AsyncStorage code easier to understand and maintain.

Note: AsyncStorage stores values as strings. Objects and arrays must be converted to JSON strings before storing and parsed after retrieving. Do not use AsyncStorage for sensitive secrets such as passwords or private authentication credentials.

1. What is AsyncStorage?

AsyncStorage is a persistent local storage mechanism commonly used in React Native applications for storing small amounts of application data.

Stored data can remain available after the application is closed and opened again.

2. Installing AsyncStorage

The community AsyncStorage package can be installed in a React Native project using the appropriate package manager.

npm install @react-native-async-storage/async-storage

In an Expo project, use the Expo-supported installation command for the package.

3. Importing AsyncStorage

import AsyncStorage from
    "@react-native-async-storage/async-storage";

After importing it, the application can use methods such as setItem(), getItem(), and removeItem().

4. AsyncStorage Stores Strings

AsyncStorage works with string values.

await AsyncStorage.setItem(
    "username",
    "Rahul"
);

The value stored under username is a string.

5. Saving a String

const saveName = async (): Promise<void> => {

    await AsyncStorage.setItem(
        "username",
        "Rahul"
    );

};

The function returns a Promise because AsyncStorage operations are asynchronous.

6. Reading a String

const name =
    await AsyncStorage.getItem(
        "username"
    );

The returned value can be a string or null when the key does not exist.

7. Typing getItem Result

const name: string | null =
    await AsyncStorage.getItem(
        "username"
    );

Using string | null accurately represents the possible result.

8. Removing Data

await AsyncStorage.removeItem(
    "username"
);

removeItem() removes the value associated with the specified key.

9. Checking for Missing Data

const name =
    await AsyncStorage.getItem(
        "username"
    );

if (name === null) {

    console.log("No username found");

} else {

    console.log(name);

}

10. Storing Boolean Values

Boolean values need to be converted to strings before storing.

const isLoggedIn: boolean = true;

await AsyncStorage.setItem(
    "isLoggedIn",
    String(isLoggedIn)
);

11. Reading a Boolean Value

const value =
    await AsyncStorage.getItem(
        "isLoggedIn"
    );

const isLoggedIn =
    value === "true";

The stored string can be converted back into a boolean.

12. Storing Numbers

Numbers must also be converted to strings before storing.

const userId: number = 101;

await AsyncStorage.setItem(
    "userId",
    String(userId)
);

13. Reading a Number

const value =
    await AsyncStorage.getItem(
        "userId"
    );

const userId =
    value === null
        ? null
        : Number(value);

The stored string can be converted back to a number.

14. Creating a User Interface

interface User {
    id: number;
    name: string;
    email: string;
}

Interfaces are useful when storing structured objects.

15. Storing an Object with JSON.stringify()

const user: User = {
    id: 101,
    name: "Rahul",
    email: "rahul@example.com"
};

await AsyncStorage.setItem(
    "user",
    JSON.stringify(user)
);

JSON.stringify() converts the object into a string.

16. Reading an Object with JSON.parse()

const value =
    await AsyncStorage.getItem(
        "user"
    );

if (value !== null) {

    const user: User =
        JSON.parse(value);

    console.log(user.name);

}

JSON.parse() converts the stored JSON string back into a JavaScript object.

17. Storing an Array

const users: User[] = [
    {
        id: 1,
        name: "Rahul",
        email: "rahul@example.com"
    },
    {
        id: 2,
        name: "Priya",
        email: "priya@example.com"
    }
];

await AsyncStorage.setItem(
    "users",
    JSON.stringify(users)
);

18. Reading an Array

const value =
    await AsyncStorage.getItem(
        "users"
    );

if (value !== null) {

    const users: User[] =
        JSON.parse(value);

    console.log(users);

}

19. AsyncStorage with useState

const [name, setName] =
    useState<string>("");

useEffect(() => {

    const loadName =
        async (): Promise<void> => {

        const value =
            await AsyncStorage.getItem(
                "username"
            );

        if (value !== null) {
            setName(value);
        }

    };

    loadName();

}, []);

20. Saving User Preferences

AsyncStorage can be used for non-sensitive application preferences.

interface Settings {
    darkMode: boolean;
    notifications: boolean;
}

const settings: Settings = {
    darkMode: true,
    notifications: true
};

await AsyncStorage.setItem(
    "settings",
    JSON.stringify(settings)
);

21. Loading User Preferences

const value =
    await AsyncStorage.getItem(
        "settings"
    );

if (value !== null) {

    const settings: Settings =
        JSON.parse(value);

    console.log(
        settings.darkMode
    );

}

22. AsyncStorage with Login State

An application can store a simple non-sensitive login preference.

await AsyncStorage.setItem(
    "loggedIn",
    "true"
);

Later, the application can read the value:

const loggedIn =
    await AsyncStorage.getItem(
        "loggedIn"
    );

23. Handling AsyncStorage Errors

try {

    await AsyncStorage.setItem(
        "username",
        "Rahul"
    );

} catch (error) {

    console.log(
        "Storage error:",
        error
    );

}

Error handling is useful because storage operations are asynchronous.

24. Common AsyncStorage TypeScript Mistakes

  • Trying to store objects directly instead of using JSON.stringify().
  • Forgetting that getItem() can return null.
  • Assuming stored numbers are automatically returned as numbers.
  • Assuming stored booleans are automatically returned as booleans.
  • Using any for structured storage data.
  • Forgetting to handle asynchronous operations.
  • Storing sensitive secrets in ordinary AsyncStorage.

25. Best Practices

  • Create interfaces for structured stored data.
  • Use JSON.stringify() for objects and arrays.
  • Use JSON.parse() when retrieving structured data.
  • Handle null values from getItem().
  • Use try/catch for storage operations.
  • Keep storage keys consistent.
  • Use AsyncStorage for appropriate non-sensitive data.

26. Creating Storage Helper Functions

Reusable helper functions can make storage code easier to maintain.

const saveUser = async (
    user: User
): Promise<void> => {

    await AsyncStorage.setItem(
        "user",
        JSON.stringify(user)
    );
};

const getUser = async ():
    Promise<User | null> => {

    const value =
        await AsyncStorage.getItem(
            "user"
        );

    if (value === null) {
        return null;
    }

    return JSON.parse(value) as User;
};

27. Removing Stored User Data

const removeUser = async (): Promise<void> => {

    await AsyncStorage.removeItem(
        "user"
    );

};

A helper function keeps the removal logic reusable.

28. Complete TypeScript AsyncStorage Example

import React, {
    useEffect,
    useState
} from "react";

import {
    View,
    Text,
    Button,
    StyleSheet
} from "react-native";

import AsyncStorage from
    "@react-native-async-storage/async-storage";

interface User {
    id: number;
    name: string;
    email: string;
}

const STORAGE_KEY = "user";

export default function App(): React.JSX.Element {

    const [user, setUser] =
        useState<User | null>(null);

    const [loading, setLoading] =
        useState<boolean>(false);

    const saveUser = async (): Promise<void> => {

        const newUser: User = {
            id: 101,
            name: "Rahul",
            email: "rahul@example.com"
        };

        try {

            setLoading(true);

            await AsyncStorage.setItem(
                STORAGE_KEY,
                JSON.stringify(newUser)
            );

            setUser(newUser);

        } catch (error) {

            console.log(
                "Unable to save user",
                error
            );

        } finally {

            setLoading(false);

        }
    };

    const loadUser = async (): Promise<void> => {

        try {

            const value =
                await AsyncStorage.getItem(
                    STORAGE_KEY
                );

            if (value !== null) {

                const storedUser =
                    JSON.parse(value) as User;

                setUser(storedUser);

            }

        } catch (error) {

            console.log(
                "Unable to load user",
                error
            );

        }
    };

    const removeUser = async (): Promise<void> => {

        try {

            await AsyncStorage.removeItem(
                STORAGE_KEY
            );

            setUser(null);

        } catch (error) {

            console.log(
                "Unable to remove user",
                error
            );

        }
    };

    useEffect(() => {

        loadUser();

    }, []);

    return (
        <View style={styles.container}>

            <Text style={styles.title}>
                AsyncStorage Example
            </Text>

            {user ? (

                <View>

                    <Text>
                        ID: {user.id}
                    </Text>

                    <Text>
                        Name: {user.name}
                    </Text>

                    <Text>
                        Email: {user.email}
                    </Text>

                    <Button
                        title="Remove User"
                        onPress={removeUser}
                    />

                </View>

            ) : (

                <Button
                    title={
                        loading
                            ? "Saving..."
                            : "Save User"
                    }
                    disabled={loading}
                    onPress={saveUser}
                />

            )}

        </View>
    );
}

const styles = StyleSheet.create({

    container: {
        flex: 1,
        padding: 20,
        justifyContent: "center"
    },

    title: {
        fontSize: 24,
        fontWeight: "bold",
        marginBottom: 20
    }

});

29. Security and AsyncStorage

AsyncStorage should not be treated as a secure secret store. Applications should avoid storing sensitive credentials or secrets directly in ordinary AsyncStorage.

For sensitive authentication information, use an appropriate secure storage solution designed for the platform and application requirements.

30. Summary

AsyncStorage is useful for persisting small amounts of non-sensitive application data in React Native. TypeScript interfaces make structured storage data easier to manage.

You should now understand how to store and retrieve strings, numbers, booleans, objects, arrays, user preferences, and typed user data. You also learned JSON.stringify(), JSON.parse(), nullable results, helper functions, error handling, and basic storage security practices.

📌 Key Points

  • AsyncStorage stores string values.
  • Use setItem() to save data.
  • Use getItem() to retrieve data.
  • Use removeItem() to delete stored data.
  • Use JSON.stringify() for objects and arrays.
  • Use JSON.parse() when reading structured JSON data.
  • Remember that getItem() can return null.
  • Use TypeScript interfaces for structured storage data.
  • Use try/catch for asynchronous storage operations.
  • Do not use ordinary AsyncStorage as a secure store for sensitive secrets.

🧠 Quick Quiz

Question: Which method is used to save a string value in AsyncStorage?