Skip to content

TypeSharp - Automatically generate TypeScript interfaces 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.

License

Notifications You must be signed in to change notification settings

siyavuyachagi/typesharp

TypeSharp

License: MIT npm version npm downloads GitHub commits GitHub last commit GitHub issues 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 decorated with the [TypeSharp] attribute.

Features

Automatic Type Generation – Convert C# models to TypeScript interfaces
🎯 Custom Attribute Targeting – Use [TypeSharp] or any custom attribute
🔄 Nullable Supportstring?string | null
📦 Collection Handling – Supports List<T>, IEnumerable<T>, arrays and generic collections
🗺️ Dictionary MappingDictionary<K, V>Record<K, V>
🧬 Generic Types – Preserves generic type definitions like Response<T>Response<T>
🧬 Inheritance – Preserves class 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

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 ⚠️ ⚠️ ⚠️
File grouping
Naming control ⚠️ ⚠️
API client generation

For more docs/why-typesharp

Installation

npm install -D @siyavuyachagi/typesharp

Quick Start

1. Create an attribute to target

In your target project create the following attribute (TypeSharp)

namespace YourProject.Attribute
{
  [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum)]
  public class TypeSharpAttribute : Attribute { }
}

2. Decorate your C# models or DTOs

[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 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:

{
  "projectFiles": [
    "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

Output (app/types/user.ts):

/**
 * Auto-generated by TypeSharp
 * Generated at: 2024-12-12T10:30:00.000Z
 * Do not edit this file manually
 */

export interface User {
  id: number;
  name: string | null;
  email: string;
  roles: UserRole[];
  permissions: string[];
  createdAt: string;
}

Output (app/types/user-role.ts):

/**
 * Auto-generated by TypeSharp
 * Generated at: 2024-12-12T10:30:00.000Z
 * Do not edit this file manually
 */

export enum UserRole {
  Admin = "Admin",
  User = "User",
  Guest = "Guest",
}

Output (app/types/api-response.ts):

/**
 * Auto-generated by TypeSharp
 * Generated at: 2024-12-12T10:30:00.000Z
 * Do not edit this file manually
 */

export interface ApiResponse<T> {
  success: boolean;
  message: string | null;
  data: T;
  errors: string[];
}

For more advanced usage docs/usage

Configuration

1. Configuration Options

Option Type Default Description
projectFiles 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

Example:

C# Structure:                       TypeScript Output (singleOutputFile: false):
Backend/                           src/types/
├── DTOs/                         └── DTOs/
│   ├── UserDtos.cs               │   ├── user-dtos.ts      ← All 3 classes together
│   │   ├── UserCreateDto         │   └── product-dtos.ts   ← All 2 classes together
│   │   ├── UserUpdateDto
│   │   └── UserResponseDto
│   └── ProductDtos.cs
│       ├── ProductDto
│       └── ProductCreateDto

This means if you organize related DTOs in one C# file, they'll stay together in the generated TypeScript file! 🎯

4. Configuration File Formats

TypeSharp supports multiple configuration formats:

JSON (typesharp.config.json): (recommended)

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

TypeScript (typesharp.config.ts):

import { TypeSharpConfig } from "typesharp";

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

export default config;

JavaScript (typesharp.config.js):

module.exports = {
  projectFiles: ["C:/Users/User/Desktop/MyApp/Domain/Domain.csproj"],
  outputPath: "./src/types",
};

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. 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;
}

2. Computed Properties

TypeSharp includes expression-bodied and block getter properties in the generated output:

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; } }

    // Init-only (Planned)
    // public string Slug { get; init; }
}

Generated TypeScript:

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

3. 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[]>;
}

4. Multi-Project

Scan multiple C# projects at once:

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

5. Single Output File

Config:

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

All types will be generated in src/types/types.ts

6. Custom Naming Conventions

Config:

const config: TypeSharpConfig = {
  projectFiles: "./Backend/Backend.csproj",
  outputPath: "./src/types",
  namingConvention: {
    dir: "kebab", // ./src/types/my-feature/
    file: "camel", // myFeatureDto.ts
  },
};

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

You can also use TypeSharp programmatically:

import { generate } from "typesharp";

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

generateTypes();

Requirements

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

License

MIT © Siyavuya Chagi

Author

Siyavuya Chagi (CeeJay)


Built with ❤️ in South Africa 🇿🇦

About

TypeSharp - Automatically generate TypeScript interfaces 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.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors