Skip to main content

Your first program and type errors

In this chapter, you create your first TypeScript program and experience compiling and running it.

What you learn in this chapter

  • Creating and compiling a TypeScript file
  • The TypeScript execution flow
  • Detecting and handling type errors
  • Features that make development more efficient
info

This chapter uses the development environment you set up in the previous chapter. Work inside the typescript-learning directory.

Your first TypeScript program

Step 1: Create a TypeScript file

File name: hello.ts

// Declare a variable: use a type annotation to state it is a string
let message: string = 'Hello, TypeScript!';

// Print to the console
console.log(message);

// Define a function: state the parameter and return types
function greet(name: string): string {
return `Hello, ${name}!`;
}

// Call the function
console.log(greet('World'));
console.log(greet('TypeScript'));

Detailed code explanation:

let message: string = 'Hello, TypeScript!';
  • let: the keyword for a variable declaration (a reassignable variable)
  • message: the variable name
  • : string: a type annotation (declares this variable is a string)
  • = 'Hello, TypeScript!': assigning the initial value
function greet(name: string): string {
return `Hello, ${name}!`;
}
  • function: the keyword for a function declaration
  • greet: the function name
  • (name: string): the parameter name and type (a string parameter named name)
  • : string: the return type (this function returns a string)
  • `Hello, ${name}!`: a template literal (a string that can embed variables)
  • ${name}: embedding a variable

Step 2: Compile the TypeScript

# Compile hello.ts to JavaScript
# tsc: the TypeScript Compiler
tsc hello.ts

# After compiling, a hello.js file is generated
# Let's check
ls
# hello.ts hello.js

The generated JavaScript code (hello.js):

"use strict";
// Declare a variable: use a type annotation to state it is a string
let message = 'Hello, TypeScript!';
// Print to the console
console.log(message);
// Define a function: state the parameter and return types
function greet(name) {
return `Hello, ${name}!`;
}
// Call the function
console.log(greet('World'));
console.log(greet('TypeScript'));

Key points:

  • All the type annotations (: string and so on) are removed
  • "use strict"; is added at the top (because strict is enabled by default in TypeScript 6.0)
  • let and template literals are left as is (because the default target is ES2025; up to TypeScript 5.x the default was ES5, so they were converted to var and string concatenation)
  • The JavaScript code is what ultimately runs

Step 3: Run the JavaScript

# Run the compiled JavaScript file with Node.js
node hello.js

# Result:
# Hello, TypeScript!
# Hello, World!
# Hello, TypeScript!

The big picture of the execution flow

┌─────────────┐ tsc ┌─────────────┐ node ┌─────────────┐
│ hello.ts │ ──────────> │ hello.js │ ──────────> │ Output │
│ (TypeScript)│ Compile │ (JavaScript)│ Execute │ (Console) │
└─────────────┘ └─────────────┘ └─────────────┘
Type info No types "Hello, ..."

Detecting type errors

Let's experience type-error detection, one of the main benefits of TypeScript.

Example 1: a type mismatch

File name: type-error.ts

// Declare a string variable
let userName: string = 'John';

// Valid code: assign a string value
userName = 'Jane';
console.log(userName); // 'Jane'

// Code that errors: assign a number value to a string variable
userName = 123;
// Error: Type 'number' is not assignable to type 'string'.

Let's compile it:

tsc type-error.ts

# An error message is shown:
# type-error.ts:9:1 - error TS2322: Type 'number' is not assignable to type 'string'.
#
# 9 userName = 123;
# ~~~~~~~~

How to read the error message:

  • type-error.ts:9:1: the file name, line number, and column number
  • error TS2322: the error code (TypeScript's error classification number)
  • Type 'number' is not assignable to type 'string': the content of the error
  • The relevant part is marked with ~ below

Example 2: a type error in a function argument

// A function that takes two number parameters and returns a number
function add(a: number, b: number): number {
return a + b;
}

// Valid calls
console.log(add(5, 10)); // 15

// Calls that error
console.log(add('5', '10'));
// Error: Argument of type 'string' is not assignable to parameter of type 'number'.

console.log(add(5, '10'));
// Error: Argument of type 'string' is not assignable to parameter of type 'number'.

An important setting: noEmitOnError

TypeScript has an option that controls whether a JavaScript file is generated even when there are errors.

# Generate a JavaScript file even when there are errors (the default)
tsc type-error.ts
# The error message is shown, but type-error.js is generated

# Do not generate a JavaScript file when there are errors
tsc --noEmitOnError type-error.ts
# The error message is shown and no JavaScript file is generated

Features that make development more efficient

Watch mode

A feature that watches for file changes and recompiles automatically.

# Compile in watch mode
tsc hello.ts --watch

# Or the short form
tsc hello.ts -w

# After running, the following message is shown:
# [11:30:00] Starting compilation in watch mode...
# [11:30:01] Found 0 errors. Watching for file changes.

How to use it:

  1. Start watch mode
  2. Edit and save hello.ts in your editor
  3. It recompiles automatically
  4. Press Ctrl+C to stop

Benefits:

  • You save the trouble of running the tsc command each time
  • Code changes are reflected immediately
  • Development productivity improves

ts-node (run TypeScript directly)

A tool that runs TypeScript files directly without compiling.

# Install ts-node
npm install -g ts-node

# Run a TypeScript file directly
ts-node hello.ts

# The result is shown immediately
# Hello, TypeScript!
# Hello, World!
# Hello, TypeScript!

How ts-node works:

The usual approach:
hello.ts → tsc → hello.js → node → Output

Using ts-node:
hello.ts → ts-node → Output (compiles and runs in memory)

When to use which:

  • During development: ts-node for quick verification
  • In production: compile with tsc, then run with node (better performance)

Try it: experience a type error ★

Create a TypeScript file that meets the following requirements, deliberately trigger a type error, and check the error message.

Requirements:

  1. Create a function named multiply (it takes two number parameters and returns the product)
  2. Try both a correct call and a call that triggers a type error
Hint
  1. Function definition: function multiply(a: number, b: number): number
  2. Correct call: multiply(3, 4) → 12
  3. Call that triggers a type error: multiply('3', '4') or multiply(3, '4')
  4. Compile with tsc <filename>.ts and check the error
Answer and explanation

File name: multiply.ts

// A function that takes two number parameters and returns the product
function multiply(a: number, b: number): number {
return a * b;
}

// Correct calls
console.log(multiply(3, 4)); // 12
console.log(multiply(2.5, 4)); // 10

// Calls that trigger a type error (uncomment to see the error)
// console.log(multiply('3', '4')); // Error: Argument of type 'string' is not assignable to parameter of type 'number'
// console.log(multiply(3, '4')); // Error: Argument of type 'string' is not assignable to parameter of type 'number'

Compile and run:

# Compile
tsc multiply.ts

# Run
node multiply.js
# 12
# 10

To check the error:

If you uncomment the lines with type errors and run tsc multiply.ts, you see an error like this:

multiply.ts:11:22 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

11 console.log(multiply('3', '4'));
~~~

This error message shows that TypeScript detected the type mismatch and points out exactly where the error occurred. This is one of the benefits you get from TypeScript's type safety.

Summary

What you learned in this chapter:

  • The basics of using TypeScript: create a .ts file, compile with the tsc command, run with the node command
  • Detecting type errors: TypeScript detects type mismatches at compile time
  • How to read error messages: file name, line number, error code, error content
  • More efficient development: watch mode (--watch), ts-node (direct execution)

In the next chapter, you will learn TypeScript's basic data types (number, string, boolean, arrays).

Common pitfalls for beginners

warning

Common mistakes

❌ Trying to run a TypeScript file directly with node

node hello.ts
# → SyntaxError: Cannot use import statement outside a module

Cause: Node.js cannot run TypeScript directly.

Solution:

# Approach 1: compile first, then run
tsc hello.ts && node hello.js

# Approach 2: use ts-node
npx ts-node hello.ts

❌ Changes are not reflected even though you compiled

Cause: You are running an old .js file, or you did not recompile.

Solution:

  1. Recompile with tsc hello.ts
  2. Use watch mode (tsc --watch)

❌ A JavaScript file is generated even though there is a type error

Cause: By default, TypeScript generates a JS file even when there are errors.

Solution:

# Do not generate JS when there are errors
tsc --noEmitOnError hello.ts

❌ "Cannot find name 'console'" error

Cannot find name 'console'.

Cause: The lib option is not set.

Solution: Create a tsconfig.json or run tsc --init.


Continue to Basic types. You learn TypeScript's most basic types (primitives / arrays / objects / unions).