Primitive Types in TypeScript
Several core primitive types and specialised types that are essential for specifying application structure and guaranteeing type safety are provided by TypeScript, which builds upon JavaScript’s basic types and improves them with static typing.
Core Primitive Types
The TypeScript type system provides a good representation of the JavaScript primitive types, particularly number
, string
, and boolean
. Typically, the :TypeAnnotation
syntax is used when writing type declarations.
Number
JavaScript is essentially limited to a single number
type: double-precision 64-bit floating-point values. This type is represented by TypeScript using the number
keyword, and it includes both floating-point and integer values. Only numeric values can be stored in variables designated as number
, thanks to the type annotation.
Numerical literals can be stated in binary (prefixed with 0b
), octal (prefixed with 0o
), hexadecimal (prefixed with 0x
), and base-10 decimal.
// Core Type: number
let count: number = 5; // Integer value is acceptable
let pi: number = 3.14; // Floating point value
let hexValue: number = 0xFF; // Hexadecimal value
let binaryValue: number = 0b10; // Binary value
// Attempting invalid assignment (results in a compile-time error):
// count = 'hello'; // Error: Type 'string' is not assignable to type 'number'
String
Textual data is represented by the string
type, which is basically a series of Unicode characters. Template strings, single quotes, and double quotes can all be used to define string values.
// Core Type: string
let str: string = 'Hello World'; // Single quotes
let doubleStr: string = "TypeScript is great";
let templateStr: string = `I am ${str}`; // Template string example
// Attempting invalid assignment (results in a compile-time error):
// str = 123; // Error: Type 'number' is not assignable to type 'string'
Boolean
The boolean
type is the most fundamental data type and is used to assign true
or false
as logical values.
// Core Type: boolean
let isTrue: boolean = true;
let isFalse: boolean = false;
// Attempting invalid assignment (results in a compile-time error):
// isTrue = 'false'; // Error: Type 'string' is not assignable to type 'boolean'
Special Types: ANY
As a way to get around TypeScript’s strict type system, the any
type is a special type. It is regarded as the most superior form of all.
- Flexibility:
any
can be used with any type in the system. A variable typed asany
can be assigned to anything, and a variable typed asany
can be assigned to anything else. - Lack of Type Checking: Expressions containing values that are typed as
any
are not type checked, which is crucial. In essence, you are instructing the compiler to cease analysing that particular value statically. - Warning: Using
any
is equivalent to “opting out of type checking for a variable”. Although useful when porting existing JavaScript code initially, it should be avoided whenever possible, as it makes you “fly blind”. The safer alternative toany
is oftenunknown
.
// The 'any' type
let power: any; // Type 'any' used to bypass type checking
power = '123'; // Takes string
power = 123; // Takes number
power = true; // Takes boolean
let num: number;
num = power; // 'any' is compatible with 'number'
// The compiler won't complain even if this causes a runtime error,
// because 'power' is 'any'.
console.log(power.toPrecision(3)); // Output based on JS runtime behavior (e.g., '123.000' if 'power' is 123)
NULL vs. UNDEFINED
TypeScript represents null
and undefined
, two JavaScript literals, as distinct special types. Both indicate that there is no value.
Value | Meaning (Convention) |
undefined | Something hasn’t been initialised or a variable has been declared but not assigned a value. |
null | Something is currently unavailable, or an explicit empty value assigned to clear a variable. |
By default (without strictNullChecks
), these values are subtypes of all other types, meaning they can typically be assigned to any other type. However, enabling strictNullChecks
forces you to explicitly include null
or undefined
in a type using a union type (e.g., string | null
or number | undefined
), eliminating the potential runtime issue known as the “billion dollar mistake”.
Checking for Both NULL and UNDEFINED
In practice, when checking for the absence of a value, you often do not need to distinguish between null
and undefined
. The loose equality check (==
) against null
or undefined
works for both, but using != null
is recommended to check if a value is definitely present, as it rules out both null
and undefined
simultaneously.
// Comparison behavior (using loose equality ==):
console.log(undefined == undefined); // Output: true
console.log(null == undefined); // Output: true
// Checking for the presence of a value using `!= null`
function processArg(arg: string | null | undefined) {
if (arg != null) {
// Here, 'arg' is strictly guaranteed to be a 'string',
// because `!= null` rules out both null and undefined.
console.log(`Processing string: ${arg.toUpperCase()}`);
return;
}
console.log("Argument is absent.");
}
processArg("test string");
// Output: Processing string: TEST STRING
processArg(null);
// Output: Argument is absent.
processArg(undefined);
// Output: Argument is absent.
Special Type: VOID
When a function lacks a return type, it is indicated by the void
type. Although void
functions are unable to explicitly return any other value, they always automatically return undefined
. The return type of a function is void
if it lacks an explicit return statement.
The only possible values for the void
type itself are null
or undefined
.
// The 'void' type annotation for a function that doesn't return
function logMessage(message: string): void {
console.log(message);
// Implicitly returns undefined
}
logMessage("Function called successfully.");
// Output: Function called successfully.
// Example of an invalid return (results in a compile-time error):
/*
function invalidReturn(): void {
return "I shouldn't return a value"; // Error: Type 'string' is not assignable to type 'void'.
}
*/