Overview
Use string, number, boolean, bigint, symbol, undefined, and null with clear intent.
TS Simple Types helps you describe intent in code so mistakes are caught earlier. Treat types as documentation that the compiler can verify, not as noise added after the fact.
Core Ideas
- Use TS Simple Types to make data shapes and function contracts explicit.
- Prefer precise types over broad ones, especially at module boundaries.
- Narrow unknown input before using it.
- Let compiler errors guide better modeling instead of disabling checks.
Step by Step
- Write the JavaScript shape that TS Simple Types describes.
- Add the narrowest useful type annotation.
- Use the value in a function so the compiler can verify the contract.
- Intentionally break the shape once, then read the compiler error.
Beginner Explanation
TS Simple Types teaches the first rule of TypeScript: every value has a shape, and the compiler can use that shape to warn you before runtime.
Simple annotations are useful at boundaries such as function parameters, API data, form values, and configuration objects.
Inference is also important because TypeScript can often read the value and know the type without extra writing.
Before You Start
- Before practicing TS Simple Types, write the JavaScript value or function you want to describe.
- Identify the boundary: function parameter, return value, object shape, API response, component prop, or configuration option.
- Turn on strict compiler settings when possible so weak assumptions become visible.
- Change one type at a time and read the compiler message before fixing it.
- Remember that TypeScript checks code before runtime; runtime validation is still needed for untrusted external data.
Key TypeScript Concepts
- Explicit annotations are useful at public boundaries.
- Inference keeps local code shorter when the value is obvious.
- unknown is safer than any because it forces narrowing before use.
- void means a function does not return a useful value; never means a value should not exist.
Plain-English Glossary
- Type annotation: a written type such as string, number, Lesson, or Promise<User>.
- Inference: TypeScript deciding a type from the value or usage.
- Union: a type that allows one of several choices.
- Narrowing: checking a value so TypeScript can treat it as a more specific type.
- Generic: a reusable type parameter such as T that preserves information.
- Interface: an extendable object contract.
- Type alias: a name for any type expression, including unions and object shapes.
- tsconfig: the project file that controls compiler behavior.
What You Will Learn
- Explain what kind of mistake TS Simple Types helps TypeScript catch.
- Write a small typed example and predict whether the compiler should accept or reject it.
- Read at least one compiler error and identify the expected type and actual type.
- Refactor the example so the type describes the real data more clearly.
Where You Use This in Real Projects
You use TS Simple Types in forms, API clients, React components, Node.js services, configuration files, data models, reusable utilities, validation layers, tests, and shared packages.
TypeScript is most valuable at boundaries where values move between files, functions, packages, APIs, users, databases, and UI components.
A practical team uses TypeScript to reduce accidental misuse, improve editor autocomplete, and make refactoring less risky.
Compiler and Tooling Notes
- Use strict mode for new code when possible.
- Do not turn a compiler error into any unless you understand what safety is being removed.
- Remember that TypeScript types disappear at runtime after compilation.
- Validate JSON, form data, URL params, and external API responses at runtime before trusting them.
- When a type becomes hard to read, split it into named aliases and test it with small examples.
Beginner Mental Model
Think of TS Simple Types as naming the kind of value you expect before the value travels through the program.
A type is like a small promise: if a function says it accepts a string, callers should not send a number, object, or unchecked unknown value.
Common Compiler Errors and Fixes
- Type mismatch: the value used in TS Simple Types does not match the expected type. Fix the value or correct the type model.
- Missing property: an object does not include a required field. Add the field, make it optional only if it is truly optional, or use a different type.
- Possibly null or undefined: check the value before using it, use optional chaining, or provide a fallback.
- Unsafe any: replace any with a specific type or unknown plus a narrowing check.
- No matching overload or call signature: compare the arguments you passed with the function type and adjust the call.
Real-World Pattern
type Lesson = {
slug: string;
title: string;
minutes: number;
};
function createLesson(input: Lesson): Lesson {
return {
...input,
title: input.title.trim()
};
}
- This TS Simple Types pattern uses a small type at a real boundary instead of adding types everywhere at random.
- The example keeps runtime code readable while giving the compiler enough information to catch mistakes.
- You can reuse the same pattern in API clients, form handlers, components, services, tests, and shared utilities.
Code Example
let title: string = 'TypeScript Basics';
let minutes: number = 30;
let published: boolean = true;
function cleanTitle(value: unknown): string {
if (typeof value === 'string') {
return value.trim();
}
return 'Untitled';
}
const label = `${cleanTitle(title)} - ${minutes} minutes - ${published}`;
Another Example
let title: string = 'TypeScript Basics';
let minutes: number = 30;
let published: boolean = true;
function cleanTitle(value: unknown): string {
if (typeof value === 'string') {
return value.trim();
}
return 'Untitled';
}
const label = `${cleanTitle(title)} - ${minutes} minutes - ${published}`;
More Practice Examples
Example 1: Model lesson data
type Level = 'beginner' | 'intermediate' | 'advanced';
interface Lesson {
slug: string;
title: string;
level: Level;
minutes: number;
}
const lesson: Lesson = {
slug: 'ts-practice',
title: 'TypeScript Practice',
level: 'beginner',
minutes: 30
};
- The Level union prevents accidental values such as easy or expert.
- The Lesson interface names the object shape once so it can be reused.
- The compiler checks missing properties and wrong value types before runtime.
Example 2: Narrow unknown input
function formatTitle(value: unknown): string {
if (typeof value === 'string' && value.trim() !== '') {
return value.trim();
}
return 'Untitled lesson';
}
console.log(formatTitle(' TS Functions '));
- unknown forces the function to check the value before using string methods.
- The return type tells callers they will always receive a string.
- This pattern is useful for form input, JSON, and third-party data.
Example 3: Reuse a generic response type
type ApiResult<T> =
| { ok: true; data: T }
| { ok: false; error: string };
function unwrap<T>(result: ApiResult<T>): T {
if (!result.ok) throw new Error(result.error);
return result.data;
}
- The generic T preserves the data type through the helper.
- The union makes success and failure explicit.
- The if statement narrows result before data is returned.
Beginner Practice Examples
Practice: Add a clear object type
type LessonCard = {
title: string;
level: 'beginner' | 'intermediate' | 'advanced';
complete: boolean;
};
const card: LessonCard = {
title: 'TypeScript Tutorial',
level: 'beginner',
complete: false
};
- The object type names exactly what the card needs.
- The level union prevents spelling and category mistakes.
- Changing complete to a string would produce a compiler error.
Practice: Add a safe formatter
function minutesLabel(minutes: number | null | undefined): string {
if (minutes == null) {
return 'Time not set';
}
return `${minutes} minutes`;
}
console.log(minutesLabel(35));
- The parameter allows number, null, or undefined.
- The null check handles both null and undefined.
- After the check, TypeScript knows minutes is a number.
Practice: Type a small API result
type Result<T> =
| { ok: true; data: T }
| { ok: false; error: string };
const result: Result<string[]> = {
ok: true,
data: ['HTML', 'CSS', 'TypeScript']
};
- The generic result can work with any data type.
- The ok field acts as the discriminant for narrowing.
- Failure results must include error instead of data.
Compiler Error Practice
Error 1: Wrong value type
Broken version
type Lesson = {
title: string;
minutes: number;
};
const lesson: Lesson = {
title: 'TS Basics',
minutes: '30'
};
Fixed version
type Lesson = {
title: string;
minutes: number;
};
const lesson: Lesson = {
title: 'TS Basics',
minutes: 30
};
- The broken version uses a string where the type requires a number.
- The fixed version changes the value instead of weakening the type.
- This is the kind of mistake TS Simple Types should catch before runtime.
Error 2: Possibly undefined value
Broken version
const lessons = ['HTML', 'CSS'];
const first = lessons[2];
console.log(first.toUpperCase());
Fixed version
const lessons = ['HTML', 'CSS'];
const first = lessons[2];
if (first) {
console.log(first.toUpperCase());
} else {
console.log('No lesson found');
}
- The array lookup may not find an item.
- The fixed version checks the value before using a string method.
- This habit helps with arrays, maps, query selectors, and API results.
Error 3: Unsafe unknown value
Broken version
function printTitle(value: unknown) {
console.log(value.trim());
}
Fixed version
function printTitle(value: unknown) {
if (typeof value === 'string') {
console.log(value.trim());
return;
}
console.log('Untitled');
}
- unknown cannot be used like a string until it is narrowed.
- The typeof check proves the value is a string.
- Use this pattern whenever data comes from outside your typed code.
Example Explained
- The TS Simple Types example starts with a real JavaScript value, function, object, or project setting.
- The type describes the smallest useful contract for that value.
- The compiler can then compare how the value is created, passed, and used.
- When the example narrows a value, TypeScript allows safer access only after the check.
- The best examples keep runtime behavior and type behavior easy to explain separately.
How to Read This Example
- Find the value, function, class, object, or configuration option being typed.
- Read the type from left to right and name what values are allowed.
- Look for optional properties, unions, generics, or narrowing checks.
- Change one property or argument to the wrong type and predict the compiler error.
- Fix the TS Simple Types example by improving the type model, not by hiding the error with any.
Checklist
- Let the compiler guide the design instead of silencing errors.
- Prefer unknown over any when input is not trusted yet.
- Keep shared types close to the data they describe.
Common Mistakes
- Using any to silence errors instead of modeling the data.
- Typing only the easy parts and leaving unsafe boundaries unchecked.
- Duplicating types instead of deriving them with utility types or generics.
Do and Don't
- Do: use TS Simple Types to describe real data and real function contracts.
- Do: prefer unknown over any when data has not been checked yet.
- Do: let inference help with local variables when the value is obvious.
- Don't: add complicated types that make the code harder to use than the bug they prevent.
- Don't: use type assertions to silence errors before proving the value is safe.
Practice Challenge
Type the TS Simple Types example, intentionally break one value, and read the compiler message before fixing it.
Try These Changes
- Add one missing property to the example and read the compiler error.
- Change one string literal to an invalid value and explain why TypeScript rejects it.
- Replace any with unknown, then add a narrowing check.
- Extract an inline object type into a named interface or type alias.
- Write one function that accepts the type and returns a formatted display string.
Step-by-Step Project Path
- Create one small file named after TS Simple Types and write a plain JavaScript version first.
- Add the first type at the boundary: function parameter, object shape, API result, component props, or config value.
- Intentionally break one value so you can read the compiler error in context.
- Fix the value or improve the type without using any as a shortcut.
- Add one runtime check if the value could come from a user, API, URL, file, or third-party package.
- Write a short comment for yourself explaining which bug the type prevents.
Quick Check
- Question: Do TypeScript types exist at runtime? Answer: No, they are checked before the JavaScript runs.
- Question: Why is unknown safer than any? Answer: unknown requires narrowing before you use the value.
- Question: What should you type first? Answer: Boundaries such as parameters, return values, API data, and props.
- Question: What is inference? Answer: TypeScript deciding a type from the value or context.
- Question: How should you fix most TS Simple Types errors? Answer: Adjust the value or model the type more accurately.
Debugging Checks
- Read the first compiler error carefully before changing multiple files.
- Identify the expected type and the actual type in the error message.
- Hover values in the editor to inspect inferred types.
- Check tsconfig strictness, module settings, lib settings, and included files when errors seem surprising.
- Use small temporary variables to make complicated inferred types easier to inspect.
Mini Project
Build a typed lesson summary for TS Simple Types: strings, numbers, booleans, unknown input, null handling, and one function that returns a safe display label.
Mastery Check
- You can explain what error TS Simple Types catches before runtime.
- You can narrow unknown data before using it.
- You can reuse the type safely in another function or module.