let person: string = 'Alice';
// ^^^ type annotations
// We can either use , or ; to separate properties for object type,
// and the last separator is optional.
function printCoord(pt: { x: number, y: number }) {}
function printCoord(pt: { x: number; y: number }) {}
Example sentences
When a parameter has a type annotation, arguments to that function will be checked.
Here, we annotated the parameter with a type with two properties - x and y - which are both of type number.
The parameter's type annotation is an object type.
Inference
Contextual typing
The static checker can infer the type of the elements within an array.
// No type annotations here, but TypeScript can spot the bug
const names = ["Alice", "Bob", "Eve"];
// Contextual typing for function
names.forEach(function (s) {
console.log(s.toUppercase());
Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
});
Union types
function printId(id: number | string) {}
// ^^^ union type, where `number` and `string` are union's members
Narrowing
Narrowing occurs when TypeScript can deduce a more specific type for a value based on the structure of the code.
// Narrowing example 1
function printId(id: number | string) {
console.log(id.toUpperCase());
// Error: Property 'toUpperCase' does not exist on type 'string | number'.
// Error: Property 'toUpperCase' does not exist on type 'number'.
}
function printId(id: number | string) {
if (typeof id === "string") {
// In this branch, id is of type 'string'
console.log(id.toUpperCase());
} else {
// Here, id is of type 'number'
console.log(id);
}
}
// Narrowing example 2
function welcomePeople(x: string[] | string) {
if (Array.isArray(x)) {
// Here: 'x' is 'string[]'
console.log("Hello, " + x.join(" and "));
} else {
// Here: 'x' is 'string'
console.log("Welcome lone traveler " + x);
}
}
Sometimes you’ll have a union where all the members have something in common. For example, both arrays and strings have a slice method. If every member in a union has a property in common, you can use that property without narrowing:
// The case where you don't have to narrowing types
function getFirstThree(x: number[] | string) {
return x.slice(0, 3);
}
Type alias
type Point = {
x: number;
y: number;
};
// Exactly the same as the earlier example
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
// Or use like this
type ID = number | string;
Note that aliases are only aliases - you cannot use type aliases to create different/distinct “versions” of the same type. When you use the alias, it’s exactly as if you had written the aliased type. In other words, this code might look illegal, but is OK according to TypeScript because both types are aliases for the same type:
type UserInputSanitizedString = string;
function sanitizeInput(str: string): UserInputSanitizedString {
return sanitize(str);
}
// Create a sanitized input
let userInput = sanitizeInput(getInput());
// Can still be re-assigned with a string though
userInput = "new input";
### ***Interface***
```ts
interface Point {
x: number;
y: number;
}
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
Just like when we used a type alias above, the example works just as if we had used an anonymous object type. TypeScript is only concerned with the structure of the value we passed to printCoord - it only cares that it has the expected properties. Being concerned only with the structure and capabilities of types is why we call TypeScript a structurally typed type system.
Difference between type alias and interface
The key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.
See this doc for more details.
Type Assertion
You can use a type assertion to specify a more specific type:
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
You can also use the angle-bracket syntax (except if the code is in a .tsx file), which is equivalent:
Reminder: Because type assertions are removed at compile-time, there is no runtime checking associated with a type assertion. There won’t be an exception or null generated if the type assertion is wrong.
TypeScript only allows type assertions which convert to a more specific or less specific version of a type. But not conversion that is impossible (e.g., assert a string is number)
Sometimes this rule can be too conservative and will disallow more complex coercions that might be valid. If this happens, you can use two assertions, first to any (or unknown), then to the desired type:
const a = (expr as any) as T;
Literal Types
var alignment: "left" | "right" | "center" = "center";
function compare(a, b): -1 | 0 | 1 {}
function configure(opts: Options | "auto") {}
Non-null Assertion Operator
// Assert that the foo won't be null
foo!.toUpperCase();
Practices
When possible, a new codebase should always turn strictness checks on.
Type annotations
It’s best not to add annotations when the type system would end up inferring the same type anyway.
If you’re starting out, try using fewer type annotations than you think - you might be surprised how few you need for TypeScript to fully understand what’s going on.
Much like variable type annotations, you usually don’t need a return type annotation because TypeScript will infer the function’s return type based on its return statements.
Some codebases will explicitly specify a return type for documentation purposes, to prevent accidental changes, or just for personal preference.
The type names String, Number, and Boolean (starting with capital letters) are legal, but refer to some special built-in types that will very rarely appear in your code. Always use string, number, or boolean for types.
Core features
Terminologies
Downleveling
Type annotations
Inference
Contextual typing
The static checker can infer the type of the elements within an array.
Union types
Narrowing
Narrowing occurs when TypeScript can deduce a more specific type for a value based on the structure of the code.
Type alias
function sanitizeInput(str: string): UserInputSanitizedString { return sanitize(str); }
// Create a sanitized input let userInput = sanitizeInput(getInput());
// Can still be re-assigned with a string though userInput = "new input";
Difference between type alias and interface
Type Assertion
You can use a type assertion to specify a more specific type:
You can also use the angle-bracket syntax (except if the code is in a .tsx file), which is equivalent:
TypeScript only allows type assertions which convert to a more specific or less specific version of a type. But not conversion that is impossible (e.g., assert a string is number)
Sometimes this rule can be too conservative and will disallow more complex coercions that might be valid. If this happens, you can use two assertions, first to
any
(orunknown
), then to the desired type:Literal Types
Non-null Assertion Operator
Practices
strictNullChecks
on to avoid potential bugs.Common pitfalls
The type names String, Number, and Boolean (starting with capital letters) are legal, but refer to some special built-in types that will very rarely appear in your code. Always use string, number, or boolean for types.
Invalid assignment due to literal inference.
Migrate from JavaScript