Auto-Generating TypeScript Types from PHP Classes: Connecting WordPress and TypeScript

Auto-Generating TypeScript Types from PHP Classes: Connecting WordPress and TypeScript

11/29/2024

Auto-Generating TypeScript Types from PHP Classes: Connecting WordPress and TypeScript

When you use WordPress as the backend it’s easy to deal with its regular theme structure, but when you have a TypeScript frontend it is not that easy. As you have to try and make sure that your types are going to be the same in PHP and TypeScript. For this, I came up with a types generation from PHP class types which established a clean & maintainable contract for the backend & frontend. Still in this article, I will explain and demonstrate to you how I was able to get there and some tips on it.

The Problem: Keeping Types in Sync

When you are working in a project that runs PHP (WordPress backend) and TypeScript (React frontend), then we need to have a way of managing the data structures between the two different worlds. When these types are kept manually and separately, it is easy to have bugs or end up with the server and client having different expectations.

To this end, I came up with a strategy to generate TypeScript types automatically from PHP classes. It guarantees that the types interacting with the backend also match those on the frontend, thus providing a reliable way of maintaining the contract between the two sub-systems of the application.

Step 1: Defining PHP Classes
And let’s go straight to a basic PHP class for a JSON Web Token (JWT). The class also specifies properties the token has, like time (iat), issuer (iss), valid until (exp), and user ID (uid). Here’s how it looks:


final class JWT {
    public string $iat;
    public string $iss;
    public string $exp;
    public string $uid;

    public function __construct(
        string $iat,
        string $iss,
        string $exp,
        string $uid
    ) {
        $this->exp = $exp;
        $this->iat = $iat;
        $this->iss = $iss;
        $this->uid = $uid;
    }

    public function toArray(): array {
        return [
            'iat' => $this->iat,
            'iss' => $this->iss,
            'exp' => $this->exp,
            'uid' => $this->uid,
        ];
    }
}

  

This class provides the structure of the JWT object that is to be used on the backend.

Step 2: JSON Schema Generation
I created a script that takes the class properties and creates a JSON representation of the PHP classes in order to guarantee consistent type definitions. This is the JSON file that is generated when I use the command npm run generate:types:


{
  "JWT": {
    "iat": "string",
    "iss": "string",
    "exp": "string",
    "uid": "string"
  }
}

  

The types and corresponding properties defined in the PHP classes at the backend are captured in this JSON object, which represents a schema of all classes coming from the backend. It’s time to create TypeScript types for the frontend using this JSON data.

Step 3: Generating TypeScript Types
I wrote a Node.js script that reads the JSON file and outputs TypeScript type definitions in order to convert the JSON schema into TypeScript types. The script used is:


const fs = require('fs');
const path = require('path');
const outputFile = 'react-app/types/schemas.ts';

if (!fs.existsSync(path.dirname(outputFile))) {
    fs.mkdirSync(path.dirname(outputFile), { recursive: true });
}

fs.readFile('src/Types/Schemas.json', 'utf8', (err, data) => {
    if (err) {
        console.error("Error trying to read file:", err);
        return;
    }

    const schemas = JSON.parse(data);
    let typescriptOutput = '';

    for (const className in schemas) {
        typescriptOutput += `export type ${className} = {\n`;
        for (const property in schemas[className]) {
            typescriptOutput += `    ${property}: ${schemas[className][property]},\n`;
        }
        typescriptOutput += '};\n\n';
    }

    fs.writeFile(outputFile, typescriptOutput, (err) => {
        if (err) {
            console.error("Error when trying to write types: ", err);
        } else {
            console.log("TypeScript generated successfully.");
        }
    });
});

  

The script reads the data JSON schema that has been produced and then generates indefinite TypeScript type definitions for each of the classes. For example, the TypeScript type corresponding to the JSON representation of the JWT class is as follows:


export type JWT = {
    iat: string,
    iss: string,
    exp: string,
    uid: string,
};

  

Step 4: Establishing A Trustworthy Contract
This is how I made the most of a contract between my backend (PHP) and frontend. Generating TypeScript types from PHP classes, all automated by generating Types definitions for the client side! This keeps the frontend experience directly in sync with the backend types — making mistakes less likely and speeding up development.

For instance, if a property in JWT class changes on the backend, then running the npm run generate:types will automatically refresh a related TypeScript type without need for manual synchronization.

Conclusion: A Smooth Process for Type Safety
In addition to saving time, the method of automatically creating TypeScript types from PHP class definitions lowers the possibility of inconsistent data structures between the frontend and backend. Because the types are constantly in sync, developers may build and maintain features with confidence when a consistent contract is established.

This approach maintains frontend alignment without adding unnecessary cost, which makes it especially useful in projects where the backend is constantly changing. As a result, the codebase is easier to maintain, which improves the application’s quality and the developer experience.