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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@siyavuyachagi/typesharp

v0.2.5

Published

Generate TypeScript types from C# models with TypeSharp attribute

Readme

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/FILE_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 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 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",
  "singleOutputFile": false,
  "namingConvention": "camel"
}

4. Generate TypeScript types

npx typesharp
# OR
npx typesharp generate

# ----- With options -------

# custom config
npx typesharp generate --config ./custom-config.ts
# force clean generation
npx typesharp generate --no-incremental

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 | | 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 fileUser.cs → 1 class | user.ts (1 interface) | All classes in types.ts | | Multiple classes per fileUserDtos.cs → 3 classes | user-dtos.ts (3 interfaces) | All classes in types.ts | | Mixed structureVarious 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": {
    "dev": "typesharp && nuxt dev",
    "build": "typesharp && nuxt build",
    "typesharp": "npx typesharp generate"
  }
}

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, TimeSpan | 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();

Preview

Terminal Output

Test Results

Requirements

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

License

MIT © Siyavuya Chagi

Author

Siyavuya Chagi (CeeJay)


Built with ❤️ in South Africa 🇿🇦