Basic
Downleveling
O TypeScript tem a capacidade de reescrever o código de versões mais recentes do ECMAScript para versões mais antigas, como ECMAScript 3 ou ECMAScript 5 (também conhecido como ES3 e ES5).
`Hello ${person}, today is ${date.toDateString()}!`;
// to
"Hello " + person + ", today is " + date.toDateString() + "!";Erased Types
Os tipos são inferidos pelo compilador, você não precisa explicitar o tipo de uma variável, por exemplo:
"use strict";
function greet(person, date) {
console.log("Hello ".concat(person, ", today is ").concat(date.toDateString(), "!"));
}
greet("Maddison", new Date());The primitives types
- string
- number
- boolean
- bigint
- symbol
Arrays
interface Person {
name: string;
age: number;
}
type People1 = Array<Person>; // Array is a generic type
type People2 = Person[]; // Person is interface object type
const people: People1 | People2 = [
{ name: "Maddison", age: 25 },
{ name: "Alice", age: 23 },
{ name: "Bob", age: 24 },
];Type Annotations on Variables
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
let x: [string, number];
x = ["hello", 10]; // OK
x = [10, "hello"]; // ErrorReturn Type Annotations
function greet(person: string, date: Date): string {
return `Hello ${person}, today is ${date.toDateString()}!`;
}Contextual Typing
const names = ["Alice", "Bob", "Eve"];
// The is anonymous function is inferred with based on the forEach method. Typescript knows that the forEach method accepts a function with two parameters, the first one is the item and the second one is the index.
names.forEach((item) => {
console.log(item.toUpperCase());
});Object Types
// The parameter's type annotation is an object type
function printCoord(pt: { x: number; y: number }) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });Optional Properties
interface Person {
name: string;
age?: number;
}
const person: Person = {
name: "Maddison",
};function printName(obj: { first: string; last?: string }) {
console.log(obj.last.toUpperCase()); // Error - might crash if 'obj.last' wasn't provided!
if (obj.last !== undefined) { // Object is possibly 'undefined'.
console.log(obj.last.toUpperCase()); // OK
}
console.log(obj.last?.toUpperCase()); // A safe alternative using modern JavaScript syntax:
}
printName({ first: "Bob" }); // Error
printName({ first: "Alice", last: "Alisson" }); // OKReadonly Properties
interface Person {
readonly name: string;
age?: number;
}
const person: Person = {
name: "Maddison",
};
person.name = "Alice"; // Error because name is readonlyUnion Types
The first way to combine types you might see is a union type. A union type is a type formed from two or more other types, representing values that may be any one of those types. We refer to each of these types as the union’s members.
Pode ser confuso que uma união de tipos pareça ter a interseção das propriedades desses tipos. Isso não é um acidente - o nome união vem da teoria dos tipos. O número da união | string é composta tomando a união dos valores de cada tipo. Observe que dados dois conjuntos com fatos correspondentes sobre cada conjunto, apenas a interseção desses fatos se aplica à união dos próprios conjuntos. Por exemplo, se tivéssemos uma sala com pessoas altas usando chapéus e outra sala com falantes de espanhol usando chapéus, depois de combinar essas salas, a única coisa que sabemos sobre todas as pessoas é que elas devem estar usando um chapéu.
// id can be a number or a string
function printId(id: number | string | string[]) {
if (typeof id === "string") {
console.log(id.toUpperCase()); // In this branch, id is of type 'string'
} else if (Array.isArray(x)) {
console.log("Hello, " + x.join(" and ")); // Here: 'x' is 'string[]'
} else {
console.log(id); // Here, id is of type 'number'
}
}
printId(101);// OK
printId("202"); // OK
printId(["303", "404"]); // OK
printId({ myID: 22342 }); // ErrorType Aliases
We’ve been using object types and union types by writing them directly in type annotations. This is convenient, but it’s common to want to use the same type more than once and refer to it by a single name.
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);
}
printCoord({ x: 100, y: 100 });Differences Between Type Aliases and Interfaces
Type aliases and interfaces are similar, but they have some important differences. The most important difference is that type aliases can’t be extended or implemented from (nor can they extend/implement other types).
// Interface Extends
interface Animal {
name: string
}
interface Bear extends Animal {
honey: boolean
}
const bear = getBear()
bear.name
bear.honey
// Type Alias Extends with Intersection
type Animal = {
name: string
}
type Bear = Animal & {
honey: boolean
}
const bear = getBear();
bear.name;
bear.honey;Interface Overloading
interface Window {
title: string
}
interface Window {
ts: TypeScriptAPI
}Type Alias Overloading
type Window = {
title: string
}
// Error: Duplicate identifier 'Window'.
type Window = {
ts: TypeScriptAPI
}Type Assertions
Type assertions são uma maneira de dizer ao compilador que você sabe melhor do que ele qual é o tipo de uma expressão. Type assertions tem duas formas. Uma é o "angle-bracket" syntax:
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;A outra é a sintaxe "as" que funciona da mesma forma:
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;Às vezes, essa regra pode ser muito conservadora e não permitirá coerções mais complexas que possam ser válidas. Se isso acontecer, você pode usar duas asserções, primeiro para qualquer (ou desconhecido, que apresentaremos mais adiante), depois para o tipo desejado:
const a = (expr as any) as T;Non-null Assertion Operator (Postfix !)
O operador de asserção de não nulo ! é uma maneira de dizer ao compilador que você sabe melhor do que ele que um valor não é nulo ou undefined. O operador de asserção de não nulo não tem efeito em tempo de execução. Ele é usado exclusivamente pelo compilador para remover o sinalizador de nulo ou indefinido.
function liveDangerously(x?: number | null) {
console.log(x!.toFixed()); // Move along, nothing to see here
}Type Guards
Type guards são algumas expressões que executam uma verificação em tempo de execução que garante o tipo em algum escopo. Para definir um type guard, basta definir uma função cujo tipo de retorno seja um predicado de tipo:
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}Literal Types
Literal types permitem que você especifique o valor exato de uma string ou número. Isso é útil quando você deseja limitar um valor a um conjunto específico de valores conhecidos.
type Easing = "ease-in" | "ease-out" | "ease-in-out";
class UIElement {
animate(dx: number, dy: number, easing: Easing) {
if (easing === "ease-in") {
// ...
} else if (easing === "ease-out") {
// ...
} else if (easing === "ease-in-out") {
// ...
} else {
// error! should not pass null or undefined.
}
}
}