SharpTS provides an MSBuild SDK that integrates TypeScript-to-.NET compilation directly into your build process. Instead of running sharpts --compile manually, the SDK compiles your TypeScript automatically when you run dotnet build.
Create a project file:
<Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<SharpTSEntryPoint>src/main.ts</SharpTSEntryPoint>
</PropertyGroup>
</Project>Build and run:
dotnet build
dotnet bin/Debug/net10.0/MyProject.dllThe SDK is distributed as a NuGet package. Reference it in your project file:
<Project Sdk="SharpTS.Sdk/1.0.0">Pin the SDK version across your solution:
{
"msbuild-sdks": {
"SharpTS.Sdk": "1.0.0"
}
}Then use the SDK without a version number:
<Project Sdk="SharpTS.Sdk"><Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<SharpTSEntryPoint>src/main.ts</SharpTSEntryPoint>
</PropertyGroup>
</Project><Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<!-- Required: Entry point TypeScript file -->
<SharpTSEntryPoint>src/main.ts</SharpTSEntryPoint>
<!-- Output configuration -->
<SharpTSOutputPath>$(OutputPath)</SharpTSOutputPath>
<SharpTSOutputFileName>$(AssemblyName).dll</SharpTSOutputFileName>
<!-- Compiler options -->
<SharpTSPreserveConstEnums>false</SharpTSPreserveConstEnums>
<SharpTSExperimentalDecorators>false</SharpTSExperimentalDecorators>
<SharpTSNoDecorators>false</SharpTSNoDecorators>
<SharpTSEmitDecoratorMetadata>false</SharpTSEmitDecoratorMetadata>
<SharpTSVerifyIL>false</SharpTSVerifyIL>
<SharpTSUseReferenceAssemblies>false</SharpTSUseReferenceAssemblies>
<!-- tsconfig.json path (auto-detected by default) -->
<SharpTSTsConfigPath>$(MSBuildProjectDirectory)\tsconfig.json</SharpTSTsConfigPath>
</PropertyGroup>
</Project>| Property | Description |
|---|---|
SharpTSEntryPoint |
Path to the entry point TypeScript file. Can be absolute or relative to the project directory. If not specified, the SDK attempts to read from tsconfig.json's files array. |
| Property | Default | Description |
|---|---|---|
SharpTSOutputPath |
$(OutputPath) |
Directory where the compiled DLL is written |
SharpTSOutputFileName |
$(AssemblyName).dll |
Name of the output assembly |
| Property | Default | CLI Equivalent | Description |
|---|---|---|---|
SharpTSPreserveConstEnums |
false |
--preserveConstEnums |
Keep const enum declarations in output |
SharpTSExperimentalDecorators |
false |
--experimentalDecorators |
Use Legacy (Stage 2) decorators instead of default Stage 3 |
SharpTSNoDecorators |
false |
--noDecorators |
Disable decorator support |
SharpTSEmitDecoratorMetadata |
false |
--emitDecoratorMetadata |
Emit design-time type metadata |
SharpTSVerifyIL |
false |
--verify |
Verify generated IL after compilation |
SharpTSUseReferenceAssemblies |
false |
--ref-asm |
Emit reference-assembly-compatible output |
| Property | Default | Description |
|---|---|---|
SharpTSTsConfigPath |
$(MSBuildProjectDirectory)\tsconfig.json |
Path to tsconfig.json for reading compiler options |
The SDK automatically reads tsconfig.json if present in the project directory. This provides IDE compatibility and allows sharing configuration between SharpTS and standard TypeScript tooling.
| tsconfig.json Path | Maps To | Notes |
|---|---|---|
compilerOptions.preserveConstEnums |
SharpTSPreserveConstEnums |
|
compilerOptions.experimentalDecorators |
SharpTSExperimentalDecorators |
Use Legacy (Stage 2) decorators |
compilerOptions.emitDecoratorMetadata |
SharpTSEmitDecoratorMetadata |
|
files[0] |
SharpTSEntryPoint |
First file used as entry point |
MSBuild properties take precedence over tsconfig.json values:
- Explicit MSBuild property (highest priority)
- tsconfig.json value
- Default value (lowest priority)
This allows you to use tsconfig.json for IDE compatibility while overriding specific settings in MSBuild.
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"preserveConstEnums": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"files": ["src/main.ts"]
}With this tsconfig.json, you can simplify your project file:
<Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<!-- Entry point and options read from tsconfig.json -->
</PropertyGroup>
</Project>The SDK defines these MSBuild targets:
| Target | Description |
|---|---|
SharpTSCompile |
Main compilation target. Runs before CoreCompile. |
SharpTSClean |
Removes compiled output. Runs before Clean. |
_SharpTSReadTsConfig |
Reads tsconfig.json settings. |
_SharpTSValidateInputs |
Validates entry point exists. |
You can hook into the build process:
<Target Name="BeforeSharpTSCompile" BeforeTargets="SharpTSCompile">
<Message Importance="high" Text="About to compile TypeScript..." />
</Target>
<Target Name="AfterSharpTSCompile" AfterTargets="SharpTSCompile">
<Message Importance="high" Text="TypeScript compilation complete!" />
</Target>MyProject/
├── MyProject.csproj
└── src/
└── main.ts
<Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<SharpTSEntryPoint>src/main.ts</SharpTSEntryPoint>
</PropertyGroup>
</Project>The SDK uses SharpTS's ModuleResolver to automatically discover and compile imported modules:
MyProject/
├── MyProject.csproj
├── tsconfig.json
└── src/
├── main.ts # Entry point
├── utils/
│ └── helpers.ts # Imported by main.ts
└── models/
└── person.ts # Imported by main.ts
// src/main.ts
import { formatName } from './utils/helpers';
import { Person } from './models/person';
const p = new Person("Alice", 30);
console.log(formatName(p.name));All imported modules are compiled into a single DLL automatically.
MyProject/
├── MyProject.csproj
├── tsconfig.json
└── src/
└── main.ts
<Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<!-- Entry point read from tsconfig.json -->
</PropertyGroup>
</Project>Standard MSBuild commands work transparently:
# Build in Debug mode
dotnet build
# Build in Release mode
dotnet build -c Release
# Clean output
dotnet clean
# Rebuild (clean + build)
dotnet build --no-incremental
# Publish
dotnet publish -c ReleaseFor debugging build issues:
dotnet build -v detailedThe SDK outputs errors in MSBuild-compatible format for IDE integration:
src/main.ts(15,10): error SHARPTS001: Type 'string' is not assignable to type 'number'
| Code | Category | Description |
|---|---|---|
| SHARPTS000 | General | Unclassified error |
| SHARPTS001 | Type Error | Type mismatch, invalid assignment |
| SHARPTS002 | Parse Error | Syntax error, unexpected token |
| SHARPTS003 | Module Error | Import not found, circular dependency |
| SHARPTS004 | Compile Error | IL emission failure |
| SHARPTS005 | Config Error | Invalid configuration |
"SharpTSEntryPoint must be specified"
- Set
<SharpTSEntryPoint>in your project file, or - Add a
filesarray to your tsconfig.json
"Entry point file 'X' does not exist"
- Check the path is correct relative to the project directory
- Ensure the file exists
"SharpTS compilation failed with exit code 1"
- Check the build output for specific error messages
- Use
dotnet build -v detailedfor more information
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Build
run: dotnet build -c Release
- name: Test
run: dotnet test -c Releasetrigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
version: '10.0.x'
- task: DotNetCoreCLI@2
inputs:
command: 'build'
arguments: '-c Release'
- task: DotNetCoreCLI@2
inputs:
command: 'test'
arguments: '-c Release'If you're using manual pre-build targets, migrate to the SDK:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<Target Name="CompileTypeScript" BeforeTargets="Build">
<Exec Command="sharpts --compile src/main.ts -o $(OutputPath)app.dll" />
</Target>
</Project><Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<SharpTSEntryPoint>src/main.ts</SharpTSEntryPoint>
</PropertyGroup>
</Project>- Automatic tsconfig.json integration
- Proper Clean target support
- MSBuild-compatible error output
- Simplified project file
- Version management via global.json
Error: The SDK 'SharpTS.Sdk/1.0.0' could not be resolved
- Ensure the NuGet package is available (nuget.org or private feed)
- Check your NuGet.config includes the correct package source
- Try
dotnet restorebefore building
- Check for infinite loops in TypeScript code
- Use
--timeoutif available in future versions
Error: IL verification errors with SharpTSVerifyIL=true
- This may indicate a compiler bug - please report with source code
- Disable verification as a workaround:
<SharpTSVerifyIL>false</SharpTSVerifyIL>
- Ensure the file is valid JSON (comments and trailing commas are supported)
- Check
SharpTSTsConfigPathpoints to the correct location - Use
dotnet build -v detailedto see what values were read
<Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<SharpTSEntryPoint>src/main.ts</SharpTSEntryPoint>
</PropertyGroup>
</Project>// src/main.ts
console.log("Hello from SharpTS!");
function fibonacci(n: number): number {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log("Fibonacci(10) =", fibonacci(10));<Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<SharpTSEntryPoint>src/index.ts</SharpTSEntryPoint>
<!-- Decorators are enabled by default (Stage 3) -->
<SharpTSEmitDecoratorMetadata>true</SharpTSEmitDecoratorMetadata>
<SharpTSUseReferenceAssemblies>true</SharpTSUseReferenceAssemblies>
</PropertyGroup>
</Project><Project Sdk="SharpTS.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<SharpTSEntryPoint>src/library.ts</SharpTSEntryPoint>
<!-- Decorators are enabled by default -->
</PropertyGroup>
</Project>// src/library.ts
@Namespace("MyCompany.Libraries")
class Calculator {
static add(a: number, b: number): number {
return a + b;
}
}The Calculator class will be emitted in the MyCompany.Libraries namespace.
- Execution Modes - Interpreted vs compiled mode
- .NET Integration - Consuming compiled TypeScript from C#
- Code Samples - TypeScript to C# mappings