npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

coffee-to-ts

v1.0.0

Published

Fast CoffeeScript to TypeScript converter with automatic type annotations

Readme

coffee-to-ts

npm version License: MIT Node.js Version

Fast and effective CoffeeScript to TypeScript converter with automatic type annotations.

Features

  • Type Annotations - Adds TypeScript type annotations to all functions and parameters
  • AST-Based Transformation - Uses Babel for robust code transformations
  • Import Modernization - Converts require() to ES6 import statements
  • Code Modernization - letconst, template literals, Number methods
  • ESLint Formatting - Applies proper code formatting with padding rules
  • Safe - Creates backups, validates at each step
  • Fast - Single-pass transformation (10-15x faster than iterative approaches)
  • Verbose Mode - See exactly what's happening

Installation

npm install --save-dev coffee-to-ts

Or use directly with npx:

npx coffee-to-ts src/file.coffee

Usage

CLI

# Basic usage
coffee-to-ts src/file.coffee

# Verbose mode
coffee-to-ts src/file.coffee --verbose

# Skip backup
coffee-to-ts src/file.coffee --no-backup

# Keep intermediate .js file
coffee-to-ts src/file.coffee --keep-intermediate

# Multiple files at once
coffee-to-ts src/**/*.coffee

Programmatic API

import { convertFile } from 'coffee-to-ts'

const result = await convertFile('src/file.coffee', {
  backup: true,
  verbose: false,
  keepIntermediate: false
})

console.log(`Output: ${result.outputFile}`)
console.log(`Types added: ${result.typesAdded}`)
console.log(`Imports converted: ${result.importsConverted}`)

How It Works

3-Stage Pipeline

Stage 1: Decaffeinate

  • Uses decaffeinate to convert CoffeeScript → JavaScript
  • Removes decaffeinate suggestion comments

Stage 2: TypeScript Transformation

  • Parses JavaScript to AST using @babel/parser
  • Adds type annotations to:
    • Function parameters (with callback pattern detection)
    • Return types
    • Class properties
  • Converts require() → ES6 import
  • Modernizes code patterns
  • Single-pass, all in-memory (very fast!)

Stage 3: Format & Validate

  • Applies ESLint auto-fix (using bundled config)
  • Validates with TypeScript compiler
  • Reports any remaining issues

Type Annotation Strategy

The tool uses a pragmatic approach to typing:

  • Callback patterns: (err: Error | null, data?: any) => void
  • Error parameters: Error | null
  • db.open callbacks: Special handling for (err, models, dbClose) pattern
  • All other parameters: : any (safe default)
  • Return types: Inferred from simple literals, else : any

This provides a working TypeScript baseline that you can refine with domain-specific types.

Configuration

Uses bundled ESLint config with sensible defaults including:

  • prefer-const - Converts let to const where appropriate
  • padding-line-between-statements - Blank lines after imports, before exports, between functions
  • Standard formatting rules

You can apply your own ESLint/Prettier configs after conversion.

Options

interface ConversionOptions {
  backup?: boolean          // Create .coffee.backup (default: true)
  verbose?: boolean         // Show detailed output (default: false)
  keepIntermediate?: boolean // Keep intermediate .js file (default: false)
}

Examples

Before & After

Input (CoffeeScript):

# user.coffee
class User
  constructor: (@name, @email) ->
    @createdAt = new Date()

  greet: (callback) ->
    setTimeout =>
      callback null, "Hello, #{@name}!"
    , 100

module.exports = User

Output (TypeScript):

// user.ts
class User {
  name: any
  email: any
  createdAt: any

  constructor(name: any, email: any) {
    this.name = name
    this.email = email
    this.createdAt = new Date()
  }

  greet(callback: (err: Error | null, data?: any) => void): void {
    setTimeout(() => {
      callback(null, `Hello, ${this.name}!`)
    }, 100)
  }
}

export default User

CLI Examples

Simple File

$ coffee-to-ts src/constants.coffee

✅ Conversion Complete
📁 Output: src/constants.ts
✨ Added 15 type annotations
📦 Converted 3 require() to import
✅ Applied ESLint formatting

Complex File with Verbose Output

$ coffee-to-ts src/user-service.coffee --verbose

Stage 1: Decaffeinating...
Stage 2: Transforming to TypeScript...
Stage 3: Formatting and validation...

✅ Conversion Complete
📁 Output: src/user-service.ts
✨ Added 42 type annotations
📦 Converted 5 require() to import
✅ Applied ESLint formatting
⚠️  TypeScript: Some type errors remain (refine types as needed)

Integration

In package.json scripts

{
  "scripts": {
    "convert": "coffee-to-ts",
    "convert:verbose": "coffee-to-ts --verbose"
  }
}

With other tools

# Convert then test
coffee-to-ts src/file.coffee && npm test

# Convert multiple files
find src -name "*.coffee" -exec coffee-to-ts {} \;

# Convert with custom ESLint fix after
coffee-to-ts src/file.coffee && npx eslint src/file.ts --fix

What It Fixes Automatically

Type Annotations

  • Function parameters: : any or specific patterns
  • Callback parameters: (err: Error | null, data?: any) => void
  • Return types: inferred or : any
  • Class properties: : any

Code Modernization

  • require() → ES6 import
  • letconst where not reassigned
  • parseInt()Number.parseInt()
  • Removes unnecessary Array.from()

Formatting

  • Blank lines after imports
  • Blank lines before exports
  • Blank lines between functions
  • Consistent indentation and quotes

Requires Manual Refinement

  • Domain-specific types (e.g., anyUser, string → specific unions)
  • Complex return types
  • Generic type parameters
  • Callback → async/await conversions

Why coffee-to-ts?

  • Fast: Single-pass transformation is 10-15x faster than iterative approaches
  • Pragmatic: Uses any types as a safe baseline - refine them gradually
  • Battle-tested: Successfully converts complex real-world CoffeeScript codebases
  • No config needed: Bundled ESLint config works out of the box
  • Safe: Creates backups and validates at each step

Limitations

  • Manual refinement needed: Generated any types should be replaced with specific types
  • Complex patterns: Some advanced CoffeeScript patterns may need manual adjustment
  • Not a compiler: This is a conversion tool, not a runtime transpiler

Troubleshooting

TypeScript errors after conversion

This is expected! The tool generates working TypeScript with any types. Gradually refine types:

// Generated
function getUser(id: any): any { ... }

// Refined
function getUser(id: string): Promise<User> { ... }

ESLint errors

Apply your own ESLint config after conversion:

npx eslint src/**/*.ts --fix

Import errors

Update imports in files that depend on converted modules:

// Before
const User = require('./user')

// After
import User from './user'

Related Projects

  • decaffeinate - CoffeeScript to JavaScript converter (used internally)
  • lebab - ES5 to ES6+ transformation

License

MIT © Coston Perkins

See LICENSE file for details.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines.

Quick Start for Contributors

git clone https://github.com/coston/coffee-to-ts.git
cd coffee-to-ts
npm install
npm run build
npm test

Changelog

See CHANGELOG.md for version history.

Support