freshcrate
Home > Developer Tools > typesharp

typesharp

TypeSharp CLI - Automatically generate TypeScript from C# models. Keep your frontend and backend types in perfect sync! Supports nullable types, enums, inheritance, arrays, and custom naming conventio

Description

TypeSharp CLI - Automatically generate TypeScript from C# models. Keep your frontend and backend types in perfect sync! Supports nullable types, enums, inheritance, arrays, and custom naming conventions. Perfect for ASP.NET Core + Vue/Nuxt/React projects.

README

TypeSharp

License: MIT npm version npm downloads GitHub commits GitHub last commit GitHub stars Sponsor

Generate TypeScript types from C# models with ease! TypeSharp scans your ASP.NET Core projects and automatically generates TypeScript interfaces from your C# classes and records decorated with the [TypeSharp] attribute.

Project structure: docs/project-structure

Features

  • Automatic Type Generation – Convert C# models to TypeScript interfaces
  • Record Support – Positional records, record class, record struct, and body-only records
  • Custom Attribute Targeting – Use [TypeSharp] or any custom attribute
  • Nullable Support – string? β†’ string | null
  • Collection Handling – Supports List<T>, IEnumerable<T>, arrays and generic collections
  • Dictionary Mapping – Dictionary<K, V> β†’ Record<K, V>
  • Generic Types – Preserves generic type definitions like Response<T> β†’ Response<T>
  • Inheritance – Preserves class and record inheritance using extends
  • Computed Properties – Expression-bodied and block getter properties are included
  • Naming Conventions – Convert property names (camel, pascal, snake, kebab)
  • Flexible Output – Single file or multiple files
  • Enum Support – Converts C# enums to TypeScript string enums
  • File Grouping – Preserves C# file organization (multiple classes per file stay together)
  • Auto Imports – Automatically generates import type statements between output files
  • Multi-Project – Scan multiple .csproj files in a single run
  • Obsolete Support – [Obsolete] / [Obsolete("...")] β†’ /** @deprecated ... */ JSDoc

How TypeSharp Compares

This is not an OpenApi-based tool !

Feature TypeSharp NSwag openapi-typescript TypeGen
Direct C# parsing βœ“ βœ• βœ• βœ“
Attribute targeting βœ“ ! βœ• !
Non-API models βœ“ βœ• βœ• βœ“
Generics preserved βœ“ ! ! !
Record support βœ“ βœ• βœ• βœ•
File grouping βœ“ βœ• βœ• βœ•
Naming control βœ“ ! ! βœ•
API client generation βœ• βœ“ βœ• βœ•

Also see docs/why-typesharp

Installation

npm install -D @siyavuyachagi/typesharp

Quick Start

1. Install the NuGet attributes package

In your C# project:

dotnet add package TypeSharp.Attributes

2. Decorate your C# models or DTOs

Use [TypeSharp] on classes, records, or enums:

[TypeSharp]
public class User
{
  public int Id { get; set; }
  public string? Name { get; set; }
  public string Email { get; set; }
  public List<UserRole> Roles { get; set; }
  public List<string> Permissions { get; set; }
  public DateTime CreatedAt { get; set; }
}

[TypeSharp]
public record ProductSummary(int Id, string Name, decimal Price);

[TypeSharp]
public enum UserRole
{
  Admin,
  User,
  Guest
}

[TypeSharp]
public class ApiResponse<T>
{
  public bool Success { get; set; }
  public string? Message { get; set; }
  public T Data { get; set; }
  public List<string> Errors { get; set; }
}

3. Create a configuration file

In your frontend project run the following script

# Create TypeScript config
npx typesharp init

# ----- OR -------

# Create JSON config
npx typesharp init --format json

# Create TypeScript config (default)
npx typesharp init --format ts

# Create JavaScript config
npx typesharp init --format js

This creates typesharp.config.json:

{
  "source": [
    "C:/Users/User/Desktop/MyApp/Api/Api.csproj",
    "C:/Users/User/Desktop/MyApp/Domain/Domain.csproj"
  ],
  "outputPath": "./app/types",
  "targetAnnotation": "TypeSharp",
  "singleOutputFile": false,
  "namingConvention": "camel"
}

4. Generate TypeScript types

npx typesharp

# ----- OR -------

npx typesharp generate
# or with custom config
npx typesharp generate --config ./custom-config.ts

For more advanced usage docs/usage

Configuration

1. Configuration Options

Option Type Default Description
source string | string[] required Full path(s) to your C# .csproj file(s)
outputPath string required Where to generate TypeScript files
targetAnnotation string 'TypeSharp' C# attribute name to look for
singleOutputFile boolean false Generate one file or multiple files (see below)
namingConvention string | { dir: string, file: string } 'camel' Property/file/dir naming: kebab, camel, pascal, snake
fileSuffix string optional Suffix appended to generated file names: user-dto.ts

2. Naming Convention

namingConvention accepts either a simple string that applies to everything, or a config object for separate control over directories and files:

// Simple β€” applies to both dirs and files
{ "namingConvention": "kebab" }

// Advanced β€” separate control
{
  "namingConvention": {
    "dir": "kebab",
    "file": "camel"
  }
}

3. Output File Behavior

TypeSharp preserves your C# file organization. Here's how it works:

C# File Structure singleOutputFile: false singleOutputFile: true
One class per file
User.cs β†’ 1 class
user.ts (1 interface) All classes in types.ts
Multiple classes per file
UserDtos.cs β†’ 3 classes
user-dtos.ts (3 interfaces) All classes in types.ts
Mixed structure
Various C# files
Each C# file β†’ 1 TS file
(preserves grouping)
All classes in types.ts

4. Configuration File Formats

TypeSharp supports multiple configuration formats:

JSON (typesharp.config.json): ⭐ recommended

{
  "source": ["C:/Users/User/Desktop/MyApp/Domain/Domain.csproj"],
  "outputPath": "./src/types"
}

JavaScript (typesharp.config.js):

const config = {
  source: ["C:/Users/User/Desktop/MyApp/Domain/Domain.csproj"],
  outputPath: "./src/types",
};

export default config;

TypeScript (typesharp.config.ts): ⚠️ requires special setup

TypeScript config files require one of the following approaches:

  1. Convert to JavaScript first (recommended):

    tsc typesharp.config.ts --module nodenext
  2. Run with tsx loader:

    node --loader tsx/cjs ./node_modules/@siyavuyachagi/typesharp/bin/typesharp.js
  3. Or use a .js config file instead (simplest)

If you prefer TypeScript configs, JSON format is the easiest alternative that provides type safety through JSDoc in most editors.

Usage in package.json

Add TypeSharp to your build scripts:

{
  "scripts": {
    "generate-types": "typesharp",
    "dev": "typesharp && nuxt dev",
    "build": "typesharp && nuxt build"
  }
}

Advanced Examples

1. Records

TypeSharp supports all C# record forms. Records are emitted as TypeScript interfaces identical to classes.

Positional record:

[TypeSharp]
public record ProductSummary(int Id, string Name, decimal Price, bool IsActive);
export interface ProductSummary {
  id: number;
  name: string;
  price: number;
  isActive: boolean;
}

Positional record with nullable and collection parameters:

[TypeSharp]
public record UserRecord(int Id, string? DisplayName, List<string> Tags);
export interface UserRecord {
  id: number;
  displayName: string | null;
  tags: string[];
}

Generic positional record:

[TypeSharp]
public record PagedResult<T>(IEnumerable<T> Items, int TotalCount, int PageSize);
export interface PagedResult<T> {
  items: T[];
  totalCount: number;
  pageSize: number;
}

record class and record struct:

[TypeSharp]
public record class AddressRecord(string Street, string City, string PostalCode);

[TypeSharp]
public record struct CoordRecord(double Lat, double Lng);

Body-only record (no primary constructor):

[TypeSharp]
public record PersonRecord
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

Record inheritance:

[TypeSharp]
public record BaseEvent(Guid Id, DateTime OccurredAt);

[TypeSharp]
public record UserCreatedEvent(Guid Id, DateTime OccurredAt, string Email) : BaseEvent(Id, OccurredAt);
export interface BaseEvent {
  id: string;
  occurredAt: string;
}

export interface UserCreatedEvent extends BaseEvent {
  id: string;
  occurredAt: string;
  email: string;
}

Per-parameter attribute overrides (use the property: target β€” required by C# for primary constructor parameters):

[TypeSharp]
public record SecureRecord(
    string Name,
    [property: TypeIgnore] string Secret,
    [property: TypeAs("Date")] DateTime CreatedAt,
    [property: Obsolete("Use Name")] string LegacyName
);
export interface SecureRecord {
  name: string;
  /** @deprecated Use Name */
  legacyName: string;
  createdAt: Date;
}

[TypeIgnore], [TypeName("x")], [TypeAs("y")], and [Obsolete] on primary constructor parameters require the property: attribute target because C# must know the attribute applies to the generated property, not the constructor parameter itself.

2. With Inheritance

C#:

[TypeSharp]
public class BaseEntity
{
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; }
}

[TypeSharp]
public class Product : BaseEntity
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Generated TypeScript:

export interface BaseEntity {
  id: number;
  createdAt: string;
}

export interface Product extends BaseEntity {
  name: string;
  price: number;
}

3. Computed Properties

TypeSharp includes expression-bodied and block getter properties:

C#:

[TypeSharp]
public class PollOptionUserLinkDto
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public UserDto User { get; set; }

    // Expression-bodied
    public string? Avatar => User?.Avatar;

    // Block getter
    public string UserFirstName { get { return User.FirstName; } }
}

Generated TypeScript:

export interface PollOptionUserLinkDto {
  id: number;
  userId: number;
  user: UserDto;
  avatar: string | null;
  userFirstName: string;
}

4. Dictionary Types

C#:

[TypeSharp]
public class PermissionMap
{
    public Dictionary<string, bool> Flags { get; set; }
    public IReadOnlyDictionary<string, List<string>> RolePermissions { get; set; }
}

Generated TypeScript:

export interface PermissionMap {
  flags: Record<string, boolean>;
  rolePermissions: Record<string, string[]>;
}

5. Obsolete / Deprecated Properties

C#:

[TypeSharp]
public class Employee
{
    public int Id { get; set; }
    public string Department { get; set; }

    [Obsolete("Use Department instead.")]
    public string? DepartmentName { get; set; }

    [Obsolete]
    public string? LegacyCode { get; set; }
}

Generated TypeScript:

export interface Employee {
  id: number;
  department: string;
  /** @deprecated Use Department instead. */
  departmentName: string | null;
  /** @deprecated */
  legacyCode: string | null;
}

6. Custom Type Name Override

[TypeSharp("auth_response")]
public class AuthResponse
{
    public string AccessToken { get; set; }
    public string RefreshToken { get; set; }
}
export interface auth_response {
  accessToken: string;
  refreshToken: string;
}

7. Multi-Project

{
  "source": [
    "C:/MyApp/Api/Api.csproj",
    "C:/MyApp/Domain/Domain.csproj",
    "C:/MyApp/Contracts/Contracts.csproj"
  ],
  "outputPath": "./src/types"
}

8. Single Output File

const config: TypeSharpConfig = {
  source: "./Backend/Backend.csproj",
  outputPath: "./src/types",
  singleOutputFile: true,
};

9. Custom Naming Conventions

const config: TypeSharpConfig = {
  source: "./Backend/Backend.csproj",
  outputPath: "./src/types",
  namingConvention: {
    dir: "kebab",
    file: "camel",
  },
};

Type Mappings

Primitives & Common Types

C# Type TypeScript Type
bool boolean
byte, decimal, double, float, int, long number
DateTime, DateOnly, TimeOnly string
Guid, string string
object any

Collections

C# Type TypeScript Type
List<T>, ICollection<T>, IEnumerable<T>, T[] T[]
Dictionary<K, V>, IDictionary<K, V>, IReadOnlyDictionary<K, V> Record<K, V>

ASP.NET / File Types

C# Type TypeScript Type
IFormFile, FormFile File
IFormFileCollection File[]
FileStream, MemoryStream, Stream Blob

Programmatic Usage

import { generate } from "typesharp";

async function generateTypes() {
  await generate("./path/to/config.ts");
}

generateTypes();

Requirements

  • Node.js >= 20
  • TypeScript >= 4.5 (if using TypeScript config)

License

MIT Β© Siyavuya Chagi

Author

Siyavuya Chagi (CeeJay)


Built with ❀️ in South Africa πŸ‡ΏπŸ‡¦

Release History

VersionChangesUrgencyDate
v0.2.0## v0.2.0 - 2026-04-12 ### Summary Improved output logging and cleaner CLI experience with optimized metrics reporting, silent change detection, and automatic cleanup on uninstall. ### Added - **ESLint integration** β€” Project-wide code quality checks with TypeScript support - **Prettier formatting** β€” Automatic code formatting for consistency - **Lint scripts** β€” `npm run lint`, `npm run lint:fix`, and `npm run format` commands - **Pre-uninstall cleanup** β€” Automatically removes `High4/12/2026
v0.1.6## v0.1.6 - 2026-04-11 ### Summary Comprehensive test suite completion with full CLI testing and incremental generation validation. ### Added - **CLI module tests** β€” 14 new test cases validating `init` and `generate` commands - Config file creation in `.ts`, `.js`, and `.json` formats - Missing config file error handling - Empty source array handling - Config overwrite prevention - **Incremental generation validation** β€” 5 passing tests confirming: - File change deteHigh4/11/2026

Dependencies & License Audit

Loading dependencies...

Similar Packages

VSCode-Local-CopilotNo descriptionmain@2026-04-21
claude-terminalManage multiple Claude Code sessions in a single terminal with tabs, session persistence, multi-project workspaces, and git worktree support.main@2026-04-21
coherent-design-methodAI-powered design system generator β€” once designed, consistent UI everywhere.v0.7.15
ossatureAn open-source harness for spec-driven code generation.master@2026-04-18
tsoa-nextBuild type-safe OpenAPI APIs for Node.js using TypeScript decorators with automatic spec generation and validationtsoa-next@8.2.2