Types are not just for strings and numbers — the shape of an object can have one too. Start by defining a type for user information.

type User = {
  name: string;
  level: number;
  isActive: boolean;
};

User is not a value. It is the rule for which properties an object has.

Right. Type names conventionally start with a capital letter. Define it once and the same rule applies to values and to function parameters alike.

const user: User = {
  name: 'JavaScript',
  level: 1,
  isActive: true,
};

function showUserName(user: User) {
  console.log(user.name);
}

So it will tell me if a property is missing or the wrong kind of value.

It will. For a property that may be absent, put ? after the name.

type User = {
  name: string;
  level: number;
  nickname?: string;
};

So nickname can be left out.

And "can be left out" means the value may be undefined. On the using side, you check whether it is there before touching it.

if (user.nickname) {
  console.log(user.nickname.toUpperCase());
}

Branching just met types.

That is the interesting part. Inside that if, TypeScript knows nickname is a string.

When you want to restrict which values are allowed, a union type is the tool.

type Status = 'draft' | 'published';

const articleStatus: Status = 'draft';

Nothing but those two strings can go into Status.

Typos surface immediately, and anyone reading it learns the intent: there are exactly two states.

Writing the shape of your data and its possible states as types is a gift to whoever reads the code next. A type error is not an obstacle — it is a note telling you where the code disagrees with the rules you set.

One last piece: what to do with the values you have grouped together.