In TypeScript, variables can be declared with type annotations using the colon (:) syntax. For example: 'let name: string = "John"', 'let age: number = 25', 'let isStudent: boolean = true'. Type annotations are optional due to TypeScript's type inference, but they make the code more explicit and self-documenting.
Both interface and type are used to define custom types, but they have some differences. Interfaces are extensible through declaration merging (can be added to later), while types are not. Interfaces can only describe object shapes, while types can also create unions, intersections, and other complex types. Generally, interfaces are preferred when defining object shapes, while types are better for aliases and complex type manipulations.
Literal types are specific value types in TypeScript where you can specify the exact value a variable can have. For example: 'let direction: "north" | "south" | "east" | "west"'. This creates a type that can only have those specific string values. Literal types can be strings, numbers, or boolean values, and are often used in union types to create enumerated sets of allowed values.
Type guards are expressions that perform runtime checks to guarantee the type of a value in a scope. They can be built-in (typeof, instanceof), custom functions (user-defined type predicates using 'is'), or the 'in' operator. Type guards help TypeScript narrow down types in conditional blocks, making the code more type-safe. Example: 'function isString(value: any): value is string { return typeof value === "string"; }'
The 'never' type represents values that never occur. It is used for functions that never return (throw an error or have infinite loops), and in type operations that result in no possible values. It's a bottom type, meaning it's assignable to every type, but no type is assignable to never (except never itself). Common use cases include error handling functions and exhaustive type checks.
Enums allow defining a set of named numeric constants. There are numeric enums (default values auto-increment from 0) and string enums (must set all values explicitly). Example: 'enum Direction { North, South, East, West }' or 'enum Direction { North = "N", South = "S" }'. Enums can be used as types and values, and TypeScript provides type safety when working with enum values.
TypeScript includes several basic data types: number (for both integers and floating-point values), string (for text), boolean (true/false), null, undefined, void (absence of value), any (dynamic typing), never (never occurs), and symbol (unique identifiers). It also supports arrays, tuples, and custom types through interfaces and type aliases.
TypeScript treats null and undefined as distinct types. By default, with strict null checks enabled (strictNullChecks compiler option), you cannot assign null or undefined to a variable unless its type explicitly allows it. You can use union types to allow null or undefined values, such as 'let name: string | null = null'. This helps prevent null reference errors common in JavaScript.
Union types allow a variable to hold values of multiple types. They are created using the | operator. For example: 'let id: string | number' means id can be either a string or a number. Union types are useful when a value could be one of several types, and TypeScript will ensure type safety by only allowing operations that are valid for all possible types in the union.
Type narrowing is the process of refining types to more specific ones based on type guards and conditional checks. Common type narrowing techniques include typeof checks, instanceof operators, in operator, and custom type predicates. For example, if you have a union type 'string | number' and check typeof x === 'string', TypeScript will narrow the type to string within that conditional block.
TypeScript is a strongly typed, object-oriented programming language that builds on JavaScript. It is a superset of JavaScript that adds optional static typing, classes, interfaces, and modules. The key differences include: static typing, enhanced IDE support, object-oriented features, and compilation to JavaScript. TypeScript code needs to be compiled into JavaScript before it can be run in a browser or Node.js environment.
Type inference is TypeScript's ability to automatically determine types of variables based on their values and usage. When you declare a variable with an initial value, TypeScript will use that value to infer its type. For example, 'let name = "John"' will be inferred as string type. This reduces the need for explicit type annotations while maintaining type safety.
The 'any' type is a dynamic type that can hold values of any type. It effectively opts out of type checking for that variable. While it provides flexibility, it should be used sparingly as it defeats the purpose of TypeScript's type system. Common use cases include: working with dynamic data, gradual migration from JavaScript, and when dealing with third-party libraries without type definitions.
Type assertions are a way to tell the TypeScript compiler that you know better about the type of a value. They can be written in two ways: using angle brackets '<type>' or the 'as' keyword. For example: 'let someValue: any = "hello"; let strLength: number = (<string>someValue).length;' or 'let strLength: number = (someValue as string).length;'. They should be used sparingly and only when you have more information about a type than TypeScript can determine.
Arrays in TypeScript can be typed in two ways: using the type followed by [] (e.g., 'number[]') or using the generic Array<type> syntax (e.g., 'Array<number>'). You can also create arrays of multiple types using union types. TypeScript provides type checking for array operations and methods. Example: 'let numbers: number[] = [1, 2, 3]' or 'let numbers: Array<number> = [1, 2, 3]'.