newtype 0.5.1

dotnet add package newtype --version 0.5.1
                    
NuGet\Install-Package newtype -Version 0.5.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="newtype" Version="0.5.1">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="newtype" Version="0.5.1" />
                    
Directory.Packages.props
<PackageReference Include="newtype">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add newtype --version 0.5.1
                    
#r "nuget: newtype, 0.5.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package newtype@0.5.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=newtype&version=0.5.1
                    
Install as a Cake Addin
#tool nuget:?package=newtype&version=0.5.1
                    
Install as a Cake Tool

newtype (Distinct Type Aliases for C#)

logo, a stylized N with a red and blue half

A source generator that creates distinct type aliases with full operator, constructor, and member forwarding. Inspired by Haskell's newtype. Works with primitives, structs, records, and classes.

dotnet add package newtype

Quick Start

using newtype;

// Typed IDs — no more mixing up int parameters
[newtype<int>]
public readonly partial struct PlayerId;

// Domain quantities — Position and Velocity can't be accidentally swapped
[newtype<Vector3>]
public readonly partial struct Position;

[newtype<Vector3>]
public readonly partial struct Velocity;

// Rich string aliases — all string operations forwarded
[newtype<string>]
public readonly partial struct Email;

Everything works as you'd expect:

var id = new PlayerId(42);
PlayerId next = id + 1;                    // arithmetic forwarded

var pos = new Position(1, 2, 3);           // constructor forwarded from Vector3
Console.WriteLine(pos.X);                  // instance members forwarded
Position origin = Position.Zero;           // static members forwarded

Email addr = "alice@example.com";          // implicit conversion from string
string raw = addr;                         // implicit conversion to string
Email greeting = addr + " (verified)";     // string concatenation works

void Move(Position p, Velocity v) { ... }
Move(velocity, position);                  // compile error — type safety!

What Gets Generated

For each [newtype<T>] partial struct, the generator emits:

Category What
Core Backing field, Value property, constructor from T, forwarded constructors
Conversions Implicit operators both ways (T ↔ alias)
Operators Binary (+ - * / % & \| ^ << >>), unary (- + ! ~ ++ --), comparison, equality
Static members Properties and readonly fields (e.g. Vector3.UnitXPosition.UnitX)
Instance members Properties and methods (e.g. .X, .Length())
Interfaces IEquatable<T>, IComparable<T>, IFormattable (when the aliased type implements them)

All generated members use [MethodImpl(MethodImplOptions.AggressiveInlining)] by default for zero-cost abstraction.

Constraining Generation

Use NewtypeOptions to suppress features, and MethodImpl to control inlining:

// No implicit int -> PlayerId (must use constructor)
[newtype<int>(Options = NewtypeOptions.NoImplicitWrap)]
public readonly partial struct PlayerId;

// No implicit conversions either way
[newtype<int>(Options = NewtypeOptions.NoImplicitConversions)]
public readonly partial struct OpaqueId;

// Fully locked down — no conversions, no forwarded constructors
[newtype<Vector3>(Options = NewtypeOptions.Opaque)]
public readonly partial struct StrictPosition;

// Let the JIT decide about inlining (omit [MethodImpl] entirely)
[newtype<int>(MethodImpl = default)]
public readonly partial struct RelaxedId;

NewtypeOptions Flags

Flag Effect
None All features enabled (default)
NoImplicitWrap Suppress T → alias implicit conversion
NoImplicitUnwrap Suppress alias → T implicit conversion
NoConstructorForwarding Suppress forwarded constructors from T
NoImplicitConversions NoImplicitWrap \| NoImplicitUnwrap
Opaque NoImplicitConversions \| NoConstructorForwarding

With any option, the primary constructor (new Alias(T value)) and .Value property are always available.

Extending Your Types

Since the alias is a partial struct, you can add custom members:

[newtype<Vector3>]
public readonly partial struct Position
{
    public static Position operator +(Position p, Velocity v)
        => new(p.Value + v.Value);
}

Viewing Generated Code

Enable generated file output in your project:

<PropertyGroup>
  <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>

Then inspect obj/Debug/net10.0/GeneratedFiles/ after building.

Requirements

  • .NET 8+ SDK
  • C# 11+ (for generic attributes [newtype<T>]; a [newtype(typeof(T))] fallback exists for older versions)

Known Limitations

Indexers, generic instance methods, ref returns, events, and nested types are not forwarded. PRs welcome!

License

MIT

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.5.1 26 2/1/2026
0.5.0 28 2/1/2026
0.4.0 26 2/1/2026
0.3.0 49 2/1/2026
0.2.0 34 1/31/2026
0.1.0 35 1/31/2026