基础类型
布尔值 boolean、数字 number、字符串 string
let isBoy: boolean = true;
let age: number = 18;
let name: string = "pbstar";
数组 Array
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
元组 Tuple 元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
let infoList: [string, number] = ["pbstar", 18];
枚举 enum
使用枚举我们可以定义一些有名字的数字常量。枚举通过 enum 关键字来定义。
默认情况下,从 0 开始为元素编号。可以手动的指定成员的数值。
enum Color {
Red = 1,
Green,
Blue,
}
let colorName: string = Color[2]; // Green
枚举成员可以是常数或计算得出的值:
enum FileAccess {
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
G = "123".length, // 计算得出的成员
}
枚举在运行时真正存在,支持双向映射(name ↔ value):
enum Enum {
A,
}
let a = Enum.A; // 0
let nameOfA = Enum[a]; // "A"
symbol 类型 symbol 类型是 ES6 引入的新类型,用于表示唯一的标识符。
let sym1: symbol = Symbol("key");
let sym2: symbol = Symbol("key");
sym1 === sym2; // false
任意值 any,空值 void,Null,Undefined any 可以赋值任意类型,void 只能赋值 undefined 和 null,Null 和 Undefined 类型的值只有它们本身。
无值 Never
类型断言
类型断言有两种形式。 其一是"尖括号"语法,另一个为"as"语法。
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
let strLength: number = (someValue as string).length;
接口 interface
接口(Interface) 用于定义对象的类型结构,描述了对象应该具有的属性和方法。
基本语法
interface Person {
name: string;
age: number;
}
let person: Person = {
name: "pbstar",
age: 18,
};
可选属性
在属性名后加 ? 表示该属性是可选的:
interface Person {
name: string;
age?: number; // 可选属性
}
let person1: Person = { name: "pbstar" }; // 合法
let person2: Person = { name: "pbstar", age: 18 }; // 合法
只读属性
在属性名前加 readonly 表示该属性是只读的:
interface Person {
readonly id: number;
name: string;
}
let person: Person = { id: 1, name: "pbstar" };
person.id = 2; // 错误!id 是只读属性
函数类型
接口可以描述函数类型:
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc = function (source: string, subString: string) {
return source.search(subString) > -1;
};
可索引类型
接口可以描述具有索引签名的对象:
interface StringArray {
[index: number]: string;
}
let myArray: StringArray = ["pbstar", "typescript"];
let myStr: string = myArray[0]; // "pbstar"
接口继承
接口可以相互继承,实现代码复用:
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square: Square = {
color: "blue",
sideLength: 10,
};
混合类型
接口可以描述同时具有多种类型的对象:
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = function (start: number) {
return String(start);
} as Counter;
counter.interval = 123;
counter.reset = function () {};
return counter;
}
类 class
类(Class) 是面向对象编程的核心概念,TypeScript 提供了基于类的面向对象编程方式。
基本语法
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
console.log(greeter.greet()); // "Hello, world"
类的继承
使用 extends 关键字实现类的继承:
class Animal {
name: string;
constructor(theName: string) {
this.name = theName;
}
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log("Woof! Woof!");
}
}
const dog = new Dog("Buddy");
dog.bark(); // "Woof! Woof!"
dog.move(10); // "Buddy moved 10m."
访问修饰符
TypeScript 提供了三种访问修饰符:
public(默认)
成员默认为 public,可以自由访问:
class Animal {
public name: string;
public constructor(theName: string) {
this.name = theName;
}
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
private
私有成员不能在声明它的类的外部访问:
class Animal {
private name: string;
constructor(theName: string) {
this.name = theName;
}
}
new Animal("Cat").name; // 错误: 'name' 是私有的
protected
受保护成员在派生类中可以访问:
class Person {
protected name: string;
constructor(name: string) {
this.name = name;
}
}
class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}
只读属性
使用 readonly 关键字将属性设置为只读:
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor(theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的
参数属性
参数属性可以方便地在一个地方创建并初始化成员:
class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) {
// 参数属性会创建并初始化 name
}
}
存取器
使用 getter 和 setter 控制对成员的访问:
class Employee {
private _fullName: string = "";
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (newName && newName.length > 0) {
this._fullName = newName;
}
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
console.log(employee.fullName); // "Bob Smith"
静态属性
使用 static 关键字定义类的静态成员:
class Grid {
static origin = { x: 0, y: 0 };
calculateDistanceFromOrigin(point: { x: number; y: number }) {
let xDist = point.x - Grid.origin.x;
let yDist = point.y - Grid.origin.y;
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
}
constructor(public scale: number) {}
}
let grid1 = new Grid(1.0); // 1x scale
let grid2 = new Grid(5.0); // 5x scale
console.log(Grid.origin); // {x: 0, y: 0}
抽象类
抽象类作为其他派生类的基类使用,不能直接被实例化:
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log("roaming the earth...");
}
}
class Dog extends Animal {
makeSound(): void {
console.log("Woof! Woof!");
}
}
// let animal = new Animal(); // 错误,抽象类不能被实例化
let dog = new Dog();
dog.makeSound(); // "Woof! Woof!"
函数 function
函数(Function) 是 JavaScript 应用程序的基础,TypeScript 为 JavaScript 函数添加了额外的功能。
基本语法
TypeScript 支持命名函数和匿名函数:
// 命名函数
function add(x: number, y: number): number {
return x + y;
}
// 匿名函数
let myAdd = function (x: number, y: number): number {
return x + y;
};
完整函数类型
函数类型包含两部分:参数类型和返回值类型:
let myAdd: (x: number, y: number) => number = function (
x: number,
y: number
): number {
return x + y;
};
可选参数
在参数名后加 ? 表示该参数是可选的:
function buildName(firstName: string, lastName?: string) {
if (lastName) return firstName + " " + lastName;
else return firstName;
}
let result1 = buildName("Bob"); // "Bob"
let result2 = buildName("Bob", "Adams"); // "Bob Adams"
默认参数
为参数提供默认值:
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // "Bob Smith"
let result2 = buildName("Bob", "Adams"); // "Bob Adams"
剩余参数
使用剩余参数表示不确定数量的参数:
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
// "Joseph Samuel Lucas MacKinzie"
this 和箭头函数
使用箭头函数解决 this 问题:
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function () {
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return { suit: this.suits[pickedSuit], card: pickedCard % 13 };
};
},
};
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
console.log("card: " + pickedCard.card + " of " + pickedCard.suit);
泛型 generic
泛型(Generics) 是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
泛型函数
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString");
let output = identity("myString"); // 类型推断
泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
loggingIdentity({ length: 10, value: 3 }); // 正确
泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
return x + y;
};
命名空间 namespace
命名空间(Namespace) 用于组织代码,避免命名冲突。
基本语法
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
// 使用命名空间
let strings = ["Hello", "98052", "101"];
let validators: { [s: string]: Validation.StringValidator } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
for (let s of strings) {
for (let name in validators) {
console.log(
`"${s}" - ${
validators[name].isAcceptable(s) ? "matches" : "does not match"
} ${name}`
);
}
}
分离文件
命名空间可以分离到多个文件:
// Validation.ts
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
}
// LettersOnlyValidator.ts
namespace Validation {
const lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
}
// Test.ts
namespace Validation {
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && /^[0-9]+$/.test(s);
}
}
}
// 使用
let validator = new Validation.ZipCodeValidator();
别名
使用 import 给常用的对象起别名:
namespace Shapes {
export namespace Polygons {
export class Triangle {}
export class Square {}
}
}
import polygons = Shapes.Polygons;
let sq = new polygons.Square();