question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Generating typescript definitions?

See original GitHub issue

Hey @DanielCoulbourne,

I’m going to be working on automatically generating typescript definitions, the awesome thing about this is that for us typescript users we’ll be able to know the shape of the params object based off the route name and get alerted of any errors instantly. See below.

Anyway, my question is, would you merge this in, or should I work on creating my own package as an extension of Ziggy?

It would be an entirely optional secondary command e.g. you’d call

php artisan ziggy:generate "resources/routes.js"
php artisan ziggy:typescript "resources/types/routes.d.ts"

It would have no effect on the @routes blade directive.

image

Cheers, Matt

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

4reactions
iDevelopThingscommented, Jun 28, 2021

Sorry to dig up an old thread, I just hacked something together, it could maybe be created as a PR and merged in by somebody else 😃

I picked some pieces of current stuff and slapped them together in a way that works nicely.

First of all, yarn add @types/ziggy-js

Create a new laravel console command; I basically ripped the current ziggy:generate command and updated it to work with ts

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Tightenco\Ziggy\Ziggy;

class ZiggyTsDefinitionsCommand extends Command
{
    protected $signature = 'ziggy:ts-definitions';

    protected $description = 'Generate TS definitions for ziggy';

    protected $files;

    public function __construct(Filesystem $files)
    {
        parent::__construct();

        $this->files = $files;
    }

    public function handle()
    {
        $path            = './resources/ts/shims-ziggy.d.ts';
        $generatedRoutes = $this->generate();

        $this->makeDirectory($path);
        $this->files->put(base_path($path), $generatedRoutes);

        $this->info('File generated!');
    }

    private function generate(): string
    {
        $ziggy  = (new Ziggy(false, null));
        $routes = collect($ziggy->toArray()['routes'])
            ->map(function ($route, $key) {
                $methods = json_encode($route['methods'] ?? []);

                return <<<TYPESCRIPT
    "{$key}": {
        "uri": "{$route['uri']}",
        "methods": {$methods}
    },
TYPESCRIPT;

            })
            ->join("\n");

        return <<<TYPESCRIPT

import {Config, InputParams, Router} from "ziggy-js";

type LaravelRoutes = {
    {$routes}
    [key: string]: string;
}

declare global {
    declare interface ZiggyLaravelRoutes extends LaravelRoutes {}
    declare function route(): Router;
    declare function route(name: keyof ZiggyLaravelRoutes, params?: InputParams, absolute?: boolean, customZiggy?: Config): string;
}

export { LaravelRoutes };

TYPESCRIPT;
    }

    protected function makeDirectory($path)
    {
        if (!$this->files->isDirectory(dirname(base_path($path)))) {
            $this->files->makeDirectory(dirname(base_path($path)), 0755, true, true);
        }

        return $path;
    }
}

Create a laravel mix extension to automatically generate the definitions when changing routes/compiling - also ripped the one that’s already documented

const mix    = require('laravel-mix');
const {exec} = require('child_process');

mix.extend('ziggy', new class {
    register(config = {})
    {
        this.watch   = config.watch ?? ['routes/**/*.php'];
        this.enabled = config.enabled ?? !Mix.inProduction();
    }

    boot()
    {
        if (!this.enabled) return;

        const command = () => exec(
            `php artisan ziggy:ts-definitions`,
            (error, stdout, stderr) => console.log(stdout)
        );

        command();

        if (Mix.isWatching() && this.watch) {
            ((require('chokidar')).watch(this.watch))
                .on('change', (path) => {
                    console.log(`${path} changed...`);
                    command();
                });
        }
    }
}());

In webpack.mix.js

mix
    .js('resources/ts/app.ts', 'public/js')
    .vue({
        version : 3,
    })
    .ziggy();

Now… when you build, this shims-ziggy.d.ts file will be generated with the following content:

import {Config, InputParams, Router} from "ziggy-js";

type LaravelRoutes = {
        "login": {
        "uri": "login",
        "methods": ["GET","HEAD"]
    },
    [key: string]: string;
}

declare global {
    declare interface ZiggyLaravelRoutes extends LaravelRoutes {}
    declare function route(): Router;
    declare function route(name: keyof ZiggyLaravelRoutes, params?: InputParams, absolute?: boolean, customZiggy?: Config): string;
}

export { LaravelRoutes };

Boom 😄

image

2reactions
francislavoiecommented, Jul 7, 2021

@iDevelopThings That’s amazing! Thank you!

A few minor adjustments to avoid some TS errors:

        return <<<TYPESCRIPT

            import {Config, InputParams, Router} from "ziggy-js";

            type LaravelRoutes = {
                [key: string]: { uri: string, methods: string[] };
            {$routes}
            }

            declare global {
                interface ZiggyLaravelRoutes extends LaravelRoutes {}
                function route(): Router;
                function route(name: keyof ZiggyLaravelRoutes, params?: InputParams, absolute?: boolean, customZiggy?: Config): string;
            }

            export { LaravelRoutes };

            TYPESCRIPT;
  • Use the routes type [key: string]: { uri: string, methods: string[] }; which is more correct than [key: string]: string;

  • Remove declare from each item inside of declare global, which gives error TS1038: A 'declare' modifier cannot be used in an already ambient context., it’s essentially redundant since declare global already says declare.

  • Untab {$routes} by one step which makes it aligned properly in the output (avoids the double indentation)

  • Tab in the heredoc (which is possible since PHP 7.3, see https://wiki.php.net/rfc/flexible_heredoc_nowdoc_syntaxes)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Documentation - Creating .d.ts Files from .js files - TypeScript
Run the TypeScript compiler to generate the corresponding d.ts files for JS files; (optional) Edit your package.json to reference the types. Adding TypeScript....
Read more >
Generating TypeScript definition files directly from the source
Generating type definitions for a JavaScript module. For this we can use dts-gen which is a tool that generates definition files from any...
Read more >
TypeScript Definition Generator 2019
To generate a .d.ts file, right-click any .cs or .vb file and select Generate TypeScript Definition. ... A .d.ts file is created and...
Read more >
How to generate TypeScript definition file from any .js file?
In this article, we will see how to generate a TypeScript definition file from any .js file or any normal TypeScript file.
Read more >
Generating TypeScript Definition Files from JavaScript
Generate TypeScript Definition Files for JSDoc Annotated JavaScript · Write your code in JS and apply JSDoc where needed · Use the forked ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found