Question

TypeScript Class Initialization and Field Initializers

Question

In TypeScript, how can I create and initialize a new class instance in a way similar to this C# example?

// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after

I want to know the TypeScript equivalent for creating a class and setting its fields during initialization.

Short Answer

By the end of this page, you will understand how TypeScript initializes class instances, why C#-style object initializers do not exist in the same form, and which TypeScript patterns to use instead. You will see practical approaches using constructors, parameter objects, and Object.assign() to set fields clearly and safely.

Concept

TypeScript classes look similar to classes in C# or Java, but object creation works differently.

In C#, you can write an object initializer like this:

new MyClass { Field1 = "ASD", Field2 = "QWE" }

That syntax creates an instance and then assigns properties in one expression.

In TypeScript, there is no direct equivalent for class instances using that exact syntax. Instead, developers usually use one of these patterns:

  • Constructor parameters
  • A constructor that accepts an object
  • Object.assign() after creating the instance
  • Plain object literals when a full class is not necessary

This matters because initialization is one of the most common parts of application code. Good initialization patterns make code:

  • easier to read
  • safer to use
  • easier to validate
  • easier to maintain as classes grow

TypeScript also adds type checking, so the way you initialize fields affects how much help you get from the compiler.

Mental Model

Think of a class like a blueprint for building an object.

  • In C# object initializer syntax, you say: “Build the object, and while doing that, fill these labeled slots.”
  • In TypeScript, you usually either:
    • hand the values to the constructor when building it, or
    • build the object first and then copy values into it.

A simple analogy:

  • Constructor approach: ordering a sandwich by listing ingredients when you place the order.
  • Object.assign() approach: getting the sandwich first, then adding ingredients afterward.

Both work, but the constructor approach is usually clearer when some values are required.

Take Quiz

Syntax and Examples

Common TypeScript patterns

1. Use a constructor with parameters

class MyClass {
  field1: string;
  field2: string;

  constructor(field1: string, field2: string) {
    this.field1 = field1;
    this.field2 = field2;
  }
}

const item = new MyClass("ASD", "QWE");

This is the most direct TypeScript version when the fields are required.

2. Use parameter properties for shorter syntax

class MyClass {
  constructor(
    public field1: string,
    public field2: string
  ) {}
}

const item = new MyClass("ASD", "QWE");

This is a common TypeScript shortcut. Writing public field1: string inside the constructor both:

  • declares the property
  • assigns the constructor argument to it

3. Accept an object in the constructor

This is often the closest practical replacement for C#-style initialization.

class MyClass {
  field1: string;
  field2: string;

  constructor(data: { field1: string; field2: string }) {
    this.field1 = data.field1;
    this.field2 = data.field2;
  }
}

const item = new MyClass({ field1: "ASD", field2: "QWE" });

This is readable because named fields are passed clearly.

4. Use Object.assign()

class MyClass {
  field1 = "";
  field2 = "";
}

const item = Object.assign(new MyClass(), {
  field1: "ASD",
  field2: "QWE"
});

This is probably the closest visual pattern to the C# example. It:

  1. creates a new instance
  2. copies properties from the object into that instance

5. Use a plain object if you do not need class behavior

type MyClassLike = {
  field1: string;
  field2: string;
};

const item: MyClassLike = {
  field1: "ASD",
  field2: "QWE"
};

If you only need data and no methods, a plain object is often simpler than a class.

Step by Step Execution

Consider this example:

class MyClass {
  field1 = "";
  field2 = "";
}

const item = Object.assign(new MyClass(), {
  field1: "ASD",
  field2: "QWE"
});

Here is what happens step by step:

  1. class MyClass defines a blueprint for objects.
  2. field1 = "" gives every new instance a default empty string.
  3. field2 = "" does the same for field2.
  4. new MyClass() creates a fresh instance:
{ field1: "", field2: "" }
  1. Object.assign(..., { field1: "ASD", field2: "QWE" }) copies the provided values into that instance.
  2. The final result stored in item becomes:
{ field1: "ASD", field2: "QWE" }

Now compare that with a constructor-based version:

class MyClass {
  constructor(
    public field1: string,
    public field2: string
  ) {}
}

const item = new MyClass("ASD", "QWE");

Step by step:

  1. The class is defined.
  2. new MyClass("ASD", "QWE") creates a new instance.
  3. The first argument is assigned to field1.
  4. The second argument is assigned to field2.
  5. The final instance contains those values.

This approach is more structured when the fields are required.

Real World Use Cases

TypeScript class initialization appears in many real applications.

API response models

class User {
  constructor(
    public id: number,
    public name: string
  ) {}
}

const user = new User(1, "Alice");

Used when turning raw API data into structured objects.

Configuration objects

class AppConfig {
  constructor(
    public apiUrl: string,
    public timeoutMs: number
  ) {}
}

const config = new AppConfig("/api", 5000);

Useful when an application needs required settings at startup.

Form or UI state containers

class LoginState {
  constructor(
    public email: string,
    public password: string
  ) {}
}

Helps organize related values into one unit.

Default values with overrides

class ButtonOptions {
  label = "Submit";
  disabled = false;
}

const options = Object.assign(new ButtonOptions(), {
  disabled: true
});

This is useful when most fields have defaults, but some need custom values.

Take Quiz

Real Codebase Usage

In real projects, developers usually choose initialization style based on how strict the data should be.

Common patterns

Constructor for required fields

Use this when an instance is invalid without certain values.

class Product {
  constructor(
    public id: number,
    public name: string
  ) {}
}

This ensures every Product has an id and name.

Parameter object for readability

When there are many options, positional constructor arguments become hard to read.

type ProductData = {
  id: number;
  name: string;
  inStock: boolean;
};

class Product {
  id: number;
  name: string;
  inStock: boolean;

  constructor(data: ProductData) {
    this.id = data.id;
    this.name = data.name;
    this.inStock = data.inStock;
  }
}

This avoids remembering argument order.

Defaults plus overrides

class RequestOptions {
  method = "GET";
  timeout = 3000;
}

const options = Object.assign(new RequestOptions(), {
  timeout: 10000
});

This pattern is common for configuration objects.

Validation inside the constructor

class User {
  constructor(public email: string) {
    if (!email.includes("@")) {
      throw new Error("Invalid email");
    }
  }
}

This keeps objects from being created in an invalid state.

Guard clauses and early validation

Developers often validate incoming data before assigning it.

class Order {
  constructor(public total: number) {
    if (total < 0) {
      throw new Error("Total cannot be negative");
    }
  }
}

This is safer than creating the object first and fixing problems later.

Common Mistakes

1. Trying to use C# syntax directly

This does not work in TypeScript:

class MyClass {
  field1 = "";
  field2 = "";
}

const item = new MyClass { field1: "ASD", field2: "QWE" };

Why it fails:

  • TypeScript does not support that object initializer syntax for classes.

Use this instead:

const item = Object.assign(new MyClass(), {
  field1: "ASD",
  field2: "QWE"
});

2. Forgetting to initialize required fields

class MyClass {
  field1: string;
  field2: string;
}

Depending on compiler settings, this can cause errors because the fields are declared but not initialized.

Better options:

class MyClass {
  field1 = "";
  field2 = "";
}

or

class MyClass {
  constructor(
    public field1: string,
    public field2: string
  ) {}
}

3. Using a class when a plain object is enough

Sometimes beginners create a class even when they only need data.

type Person = {
  name: string;
  age: number;
};

const person: Person = { name: "Sam", age: 30 };

If there is no behavior or validation, a plain object may be simpler.

4. Using too many positional constructor arguments

class Settings {
  constructor(
    public host: string,
    public port: number,
    public secure: boolean,
    public timeout: number
  ) {}
}

This works, but it becomes hard to remember the order.

Better:

class Settings {
  host: string;
  port: number;
  secure: boolean;
  timeout: number;

  constructor(data: {
    host: string;
    port: number;
    secure: boolean;
    timeout: number;
  }) {
    this.host = data.host;
    this.port = data.port;
    this.secure = data.secure;
    this.timeout = data.timeout;
  }
}

5. Assuming Object.assign() performs validation

class User {
  age = 0;
}

const user = Object.assign(new User(), { age: -100 });

Object.assign() copies values, but it does not enforce business rules. If validation matters, use a constructor or a factory function.

Comparisons

ApproachExampleBest forProsCons
Constructor parametersnew MyClass("ASD", "QWE")Required valuesSimple, strict, type-safeArgument order can become unclear
Parameter objectnew MyClass({ field1: "ASD", field2: "QWE" })Many named fieldsReadable, flexibleSlightly more code
Object.assign()Object.assign(new MyClass(), { field1: "ASD" })Defaults plus overridesClosest to C# feel, conciseLess explicit validation
Plain object literal{ field1: "ASD", field2: "QWE" }Data-only structuresVery simpleNo class methods or class-based behavior

Constructor vs Object.assign()

  • Use a constructor when values are required and the object should be valid immediately.
  • Use Object.assign() when you already have defaults and want to override some fields.

Class vs plain object

  • Use a class when you need methods, validation, or controlled creation.
  • Use a plain object when you only need to store data.
Take Quiz

Cheat Sheet

// 1. Standard constructor
class MyClass {
  field1: string;
  field2: string;

  constructor(field1: string, field2: string) {
    this.field1 = field1;
    this.field2 = field2;
  }
}

const a = new MyClass("ASD", "QWE");
// 2. Short TypeScript constructor syntax
class MyClass {
  constructor(
    public field1: string,
    public field2: string
  ) {}
}
// 3. Object-style initialization through constructor
class MyClass {
  constructor(public data: { field1: string; field2: string }) {}
}
// 4. Closest to C# initializer style
class MyClass {
  field1 = "";
  field2 = "";
}

const b = Object.assign(new MyClass(), {
  field1: "ASD",
  field2: "QWE"
});

Quick rules

  • TypeScript does not support new MyClass { ... }
  • Prefer constructors for required fields
  • Prefer parameter objects when there are many options
  • Use Object.assign() for defaults plus overrides
  • Use a plain object if you do not need class behavior

FAQ

Is there a direct equivalent to C# object initializer syntax in TypeScript?

No. TypeScript does not support new MyClass { ... } syntax. Use a constructor, an object parameter, or Object.assign() instead.

What is the closest TypeScript alternative to C# field initialization?

Object.assign(new MyClass(), { ... }) is the closest in style, because it creates an instance and then copies properties onto it.

Should I use a constructor or Object.assign()?

Use a constructor when fields are required or validation matters. Use Object.assign() when you have default values and want a quick override pattern.

Can I pass an object to a TypeScript constructor?

Yes. This is a common pattern:

new MyClass({ field1: "ASD", field2: "QWE" })

It is especially useful when there are many fields.

Do I always need a class in TypeScript?

No. If you only need to store data, a plain object or a type/interface is often enough.

Why does TypeScript complain about properties not being initialized?

With strict compiler settings, TypeScript wants proof that class properties are assigned. You can fix this by:

  • assigning default values
  • assigning them in the constructor
  • using other strict-safe initialization patterns
Take Quiz

Mini Project

Description

Create a small TypeScript model for application settings. This project demonstrates multiple initialization styles: default field values, constructor-based setup, and overriding defaults with a partial object. It reflects a real pattern used in configuration-heavy applications.

Goal

Build a UserPreferences class that starts with sensible defaults and allows selected values to be overridden during creation.

Requirements

  1. Create a UserPreferences class with at least three fields.
  2. Give each field a default value.
  3. Allow the caller to override one or more fields when creating a new instance.
  4. Return a fully initialized class instance.
  5. Show example usage with different override combinations.
Take Quiz

Keep learning

Related questions

View more