LogoRobo.js

TypeScript

Leverage TypeScript for better type safety and development experience.

Robo.js has first-class TypeScript support. There is no need to configure compilation or set up build pipelines manually. The dev and build commands handle everything, using the Rust-based SWC compiler for fast builds.

Setting Up TypeScript Projects

The create-robo CLI can scaffold a TypeScript project directly:

npx create-robo@next my-awesome-robo --ts

For existing projects, install @swc/core and typescript as dev dependencies, create a tsconfig.json file, and rename your .js files to .ts:

npm install --save-dev @swc/core typescript

Example tsconfig.json:

{
	"compilerOptions": {
		"target": "ESNext",
		"lib": ["esnext"],
		"allowJs": true,
		"skipLibCheck": true,
		"strict": true,
		"forceConsistentCasingInFileNames": true,
		"noEmit": true,
		"esModuleInterop": true,
		"module": "esnext",
		"moduleResolution": "node",
		"resolveJsonModule": true,
		"isolatedModules": true,
		"incremental": true
	},
	"include": ["**/*.ts"],
	"exclude": ["node_modules"]
}

TypeScript Types in Robo.js

Robo.js ships with native TypeScript types. Common types include Config, Plugin, and Manifest. Platform-specific types like CommandConfig and EventConfig are provided by their respective plugins (e.g., @robojs/discordjs).

Example of a typed async command:

src/commands/command.ts
import { createCommandConfig } from '@robojs/discordjs'

export const config = createCommandConfig({
	description: 'An async example command'
})

export default async () => {
	await new Promise((resolve) => setTimeout(resolve, 1000))
	return 'Waited for 1 second.'
}
src/commands/command.js
import { createCommandConfig } from '@robojs/discordjs'

export const config = createCommandConfig({
	description: 'An async example command'
})

export default async () => {
	await new Promise((resolve) => setTimeout(resolve, 1000))
	return 'Waited for 1 second.'
}

For interaction types, import directly from Discord.js:

src/commands/ts-command.ts
import { CommandInteraction } from 'discord.js'

export default (interaction: CommandInteraction) => {
	interaction.reply('Hello, TypeScript!')
}
src/commands/ts-command.js
export default (interaction) => {
	interaction.reply('Hello, TypeScript!')
}

Building Plugins with TypeScript

Plugins can be built with TypeScript for better type safety. The robo build plugin command handles compilation:

npx robo build plugin

TypeScript in Config Files

Config files use JavaScript format, but TypeScript's @type annotation comments provide type checking and autocompletion in editors like VS Code:

// config/robo.mjs
// @ts-check

/** @type {import('robo.js').Plugin} */
const gptPlugin = [
	'@robojs/ai',
	{
		// Plugin config options
	}
]

/** @type {import('robo.js').Config} */
export default {
	plugins: [gptPlugin]
}

The @ts-check and @type annotations enable autocompletion and type checking in supported editors without requiring the config file itself to be TypeScript.

Path Aliases

Path aliases simplify deep imports by replacing long relative paths with short, readable prefixes.

Add aliases to your tsconfig.json:

{
	"compilerOptions": {
		"paths": {
			"@/robo/*": ["src/*"],
			"@/something/*": ["src/modules/something/*"]
		}
	}
}

TypeScript resolves @/robo/ to src/ and @/something/ to src/modules/something/. The baseUrl defaults to the project root.

Before and after:

src/commands/example.ts
// Before
import { someVariable } from '../../../../modules/something/commands/someCommand.js'

// After
import { someVariable } from '@/something/commands/someCommand.js'
src/commands/example.js
// Before
import { someVariable } from '../../../../modules/something/commands/someCommand.js'

// After
import { someVariable } from '@/something/commands/someCommand.js'

Monorepos

Monorepos bundle multiple projects in a single repository, making code sharing straightforward. Robo.js works naturally in monorepo setups.

A typical layout:

package.json
package.json
package.json

Use path aliases to import from other packages:

{
	"compilerOptions": {
		"paths": {
			"@/api/*": ["../api/dist/*"],
			"@/robo/*": ["src/*"],
			"@/something/*": ["src/modules/something/*"]
		}
	}
}

Note: Always reference compiled files (in /dist), not raw .ts sources, when sharing code across TypeScript projects in a monorepo.

With this configuration, importing from another package works as expected:

import { someFunction } from '@/api/someFile.js'
import { someFunction } from '@/api/someFile.js'

Next Steps

On this page