TS
C#

TypeScript to C#

10 lessons

Progress0%
1Introduction: Two Languages, One Mind2Type Systems: Structural vs Nominal3Classes: Advanced Features4Generics and LINQ5Nullable Reference Types6Async/Await7Decorators to Attributes8Ecosystem9File I/O10Records and Pattern Matching
All Mirror Courses
TS
C#
Generics and LINQ
MirrorLesson 4 of 10
Lesson 4

Generics and LINQ

Generics & LINQ

Introduction

In this lesson, you'll learn about generics and linq in C#. Coming from TypeScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
TS
From TypeScript:

In TypeScript, you're familiar with generics & linq.

C#
In C#:

C# has its own approach to generics & linq, which we'll explore step by step.

The C# Way

Let's see how C# handles this concept. Here's a typical example:

C#
C# Example
// C# generics — nearly identical syntax
T? First<T>(IEnumerable<T> source) => source.FirstOrDefault();

// LINQ — functional pipeline (like TS array methods)
var result = new[] { 1, 2, 3, 4, 5 }
    .Where(n => n % 2 == 0)
    .Select(n => n * 10)
    .Sum();

// LINQ query syntax (SQL-like alternative)
var evens = from n in numbers
            where n % 2 == 0
            select n * 10;

// Generic interface with constraint
interface IRepository<T> where T : IHasId {
    T? FindById(int id);
}

Comparing to TypeScript

Here's how you might have written similar code in TypeScript:

TS
TypeScript (What you know)
// TypeScript generics
function first<T>(arr: T[]): T | undefined {
  return arr[0];
}

// Array methods as functional pipeline
const result = [1, 2, 3, 4, 5]
  .filter(n => n % 2 === 0)
  .map(n => n * 10)
  .reduce((sum, n) => sum + n, 0);

// Generic interface with constraint
interface Repository<T extends { id: number }> {
  findById(id: number): T | undefined;
}
Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

C#
In C#:

C# generics use where T : Constraint instead of TypeScript's T extends Constraint

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

C#
In C#:

LINQ .Where() = .filter(), .Select() = .map(), .Aggregate() = .reduce()

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

C#
In C#:

LINQ has both method syntax and SQL-like query syntax

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

C#
In C#:

C# generics support covariance (out T) and contravariance (in T) keywords

Step-by-Step Breakdown

1. T extends vs where T :

TypeScript uses <T extends Constraint>. C# uses <T> then a separate where T : Constraint clause at the end of the signature.

TS
TypeScript
function sort<T extends Comparable<T>>(items: T[]): T[] {}
C#
C#
IList<T> Sort<T>(IList<T> items) where T : IComparable<T> {}

2. LINQ = Array Methods

LINQ (Language Integrated Query) provides the same functional pipeline as TypeScript array methods. Where/Select/Aggregate map to filter/map/reduce.

TS
TypeScript
users.filter(u => u.age > 18).map(u => u.name)
C#
C#
users.Where(u => u.Age > 18).Select(u => u.Name)
Rule of Thumb
Prefer LINQ method syntax for functional pipelines. Use query syntax when the query reads like SQL.

3. Covariance and Contravariance

C# generic interfaces support explicit covariance (out T — read-only) and contravariance (in T — write-only). TypeScript infers variance automatically.

TS
TypeScript
// TypeScript infers variance automatically
type ReadOnly<T> = { readonly value: T };
C#
C#
// C# explicit covariance:
interface IProducer<out T> { T Produce(); }
// IProducer<Dog> is assignable to IProducer<Animal>

4. IEnumerable<T> — The Universal Sequence

C# IEnumerable<T> is the equivalent of TypeScript's Iterable<T>. All LINQ methods work on any IEnumerable<T>, including arrays, lists, and custom sequences.

TS
TypeScript
function process<T>(items: Iterable<T>): void {}
C#
C#
void Process<T>(IEnumerable<T> items) {}
// Works with: arrays, List<T>, HashSet<T>, query results

Common Mistakes

When coming from TypeScript, developers often make these mistakes:

  • C# generics use where T : Constraint instead of TypeScript's T extends Constraint
  • LINQ .Where() = .filter(), .Select() = .map(), .Aggregate() = .reduce()
  • LINQ has both method syntax and SQL-like query syntax
Common Pitfall
Don't assume C# works exactly like TypeScript. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • C# constraint syntax: where T : IConstraint instead of T extends Constraint
  • LINQ methods mirror TS array methods: Where/Select/Aggregate = filter/map/reduce
  • C# supports explicit covariance (out T) and contravariance (in T)
  • IEnumerable<T> is the universal sequence type — all LINQ methods operate on it
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your TypeScript code in C# to practice these concepts.
PreviousNext