let varName:Type= value;const varName:Type= value;
Example
let orderId: string ="ORD-7821";const maxRetries: number =3;let tags: string[]=["urgent","billing"];// Often unnecessary when the type is obviouslet count =0;// inferred as numberconst label ="total";// inferred as literal "total"
Output
// Explicit annotations override inference when needed
Note Let TypeScript infer when the type is obvious from the initializer. Add explicit annotations when: the inferred type is too wide, you are declaring without initializing, or you want documentation clarity.
functioncalculateTotal(
items:{ name: string; price: number }[],
taxRate: number
): number {const subtotal = items.reduce((sum, item)=> sum + item.price,0);return subtotal *(1+ taxRate);}
Output
// Parameters MUST be annotated - TypeScript does not infer param types
Note Function parameters are never inferred from usage. Always annotate them. The return type is usually inferred correctly, but annotating it explicitly catches mistakes when the function body changes.
function parameter typetyped functionannotate parametersfunction arguments type
Note Explicit return types are especially valuable for public API functions, async functions, and functions with multiple return paths. They also speed up type-checking in large projects since the compiler does not need to analyze the function body.
// No annotation needed - TypeScript figures it outlet varName = value;
Example
let customerName ="Kenji";// stringconst port =8080;// literal type 8080 (const narrows)let results =[1,2,3];// number[]let mixed =[1,"two",true];// (string | number | boolean)[]// Return type inferencefunctiondouble(n: number){return n *2;// inferred return: number}
Output
// const uses literal types; let uses widened types
Note const declarations infer the narrowest (literal) type, while let declarations widen to the base type. This is called 'widening'. Use 'as const' to get literal types with let, or on objects/arrays to make them deeply readonly with literal types.
type inferenceinferred typeautomatic typewideninglet vs const inference
// Assertions override the compiler - they do NOT perform runtime conversion
Note Type assertions are a compile-time escape hatch - no runtime checking or conversion happens. If you assert incorrectly, you get silent bugs. Prefer type guards (typeof, instanceof) when possible. The angle-bracket syntax <Type>value conflicts with JSX - always use 'as Type' in .tsx files.
// Caller sees the specific overload, not the implementation signature
Note The implementation signature is not callable directly - only the overload signatures are visible to callers. Order matters: TypeScript picks the first matching overload. Put more specific signatures before general ones.
function overloadmultiple signaturesoverloaded functiondifferent return types