TypeScript 是 JavaScript 的超集(超集表示前者包含了后者),扩展了 JavaScript 的语法。TypeScript 无法直接运行于浏览器上,需要编译转换成 JavaScript 才可以在浏览器上运行。
优点
缺点
先安装 node(安装方法自己网上找),然后通过 node 携带的 npm 来安装 TypeScript;
npm 安装 TypeScript 的命令如下:
npm install -g typescript
安装完成后,可以通过执行命令 tsc -v 检查安装是否成,执行命令后显示版本号即表示安装成功。
tsc -v
# Version 3.2.2
通过执行以下命令将 TypeScript 转换成 JavaScript 。(通常我们使用 .ts 作为 TypeScript 代码文件的扩展名)
tsc test.ts
执行上面命令后,会在当前目录下生成转换后的 test.js 文件。
TypeScript 包含的数据类型如下:
数字类型 number、字符串类型 string、布尔类型 boolean、数组类型、元组类型、泛型类型、枚举类型 enum、任意类型 any、null、undefined、void、nerver
用法如下:
// 数字类型(number)
let n: number = 10;
// 字符串类型(string)
let str: string = "张三";
// 布尔类型(boolean)
let b: boolean = true;
// 数组类型,这有两种方法
let arr1: string[] = ["张三", "李四", "王五"];
let arr2: Array<string> = ["张三", "李四", "王五"];
// 元组类型,
let arr: [number, string] = [10, '张三'];
// 泛型类型
interface Hello<T> {
(arg: T): T;
}
function myHello<T>(arg: T): T {
return arg;
}
// 枚举类型(enum)
enum Flag{
success,
error
}
let f: Flag = Flag.success;
console.log(f);// 0
// 任意类型
let x: any = 1; // 数字类型
x = '张三'; // 字符串类型
x = false; // 布尔类型
let arrayList: any[] = [1, false, 'fine'];
arrayList[1] = 100;
//当一个元素可能是null,可能是undefined,可能是number
let num: number| null | undefined;
num = 123;
num = null;
num = undefined;
// void一般只用于定义函数的时候用
function run1(): void {
console.log('打印');
}
function run2(): number {
return 123;
}
// never的函数可以是抛出异常的情况
function error(message: string): never {
throw new Error(message);
}
// never的函数可以是无法被执行到的终止点的情况
function loop(): never {
while (true) {}
}
类型断言可以用来手动指定一个值的类型,即允许变量从一种类型更改为另一种类型。
语法格式: <类型> 值
或者 值 as 类型
实例:
let str = '1';
let num: number = <number> <any> str;
当类型没有给出时,TypeScript 编译器利用类型推断来推断类型。
let num = 2; // 类型推断为 number
num = "12"; // 编译错误
实例:
// 固定参数
function buildName1(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
buildName1("Bob"); // 错误,缺少参数
buildName1("Bob", "Adams", "Sr."); // 错误,参数太多了
buildName1("Bob", "Adams"); // 正确
// 可选参数
function buildName2(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
buildName2("Bob"); // 正确
buildName2("Bob", "Adams", "Sr."); // 错误,参数太多了
buildName2("Bob", "Adams"); // 正确
// 剩余参数
function buildName3(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
buildName3("Joseph", "Samuel", "Lucas", "MacKinzie");
// 默认参数
function calculate_discount(price: number, rate: number = 0.50) {
let discount = price * rate;
return discount;
}
calculate_discount(1000);
calculate_discount(1000, 0.30);
接口是一系列抽象方法的声明,这些方法都应该是抽象的,需要由具体的类去实现。
实例:
interface IPerson {
firstName: string,
lastName: string,
sayHi: () => string
}
let customer: IPerson = {
firstName: "Tom",
lastName: "Hanks",
sayHi: (): string => {return "Hi there"}
}
接口和数组:
interface namelist {
[index: number]: string
}
let list2: namelist = ["John", 1, "Bran"] // 错误,元素 1 不是 string 类型
接口继承:
// 单继承
interface Person {
age: number
}
interface Musician extends Person {
instrument: string
}
let drummer = <Musician>{};
drummer.age = 27;
drummer.instrument = "Drums";
// 多继承
interface IParent1 {
v1: number
}
interface IParent2 {
v2: number
}
interface Child extends IParent1, IParent2 {}
let obj: Child = {v1: 12, v2: 23}
类描述了所创建对象的共同属性和方法。
实例:
class Car {
// 字段
engine: string;
// 构造函数
constructor(engine: string) {
this.engine = engine;
}
// 方法
disp(): void {
console.log("函数中显示发动机型号 : "+this.engine)
}
}
// 创建一个对象
let obj = new Car("XXSY1")
// 访问字段
console.log("读取发动机型号 : " + obj.engine);
// 访问方法
obj.disp();
类继承:
class Shape {
Area: number;
constructor(a: number) {
this.Area = a;
}
}
class Circle extends Shape {
disp(): void {
console.log("圆的面积: " + this.Area);
}
}
let obj = new Circle(223);
obj.disp();
static 关键字:用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。
class StaticMem {
static num: number;
static disp(): void {
console.log("num 值为 " + StaticMem.num);
}
}
StaticMem.num = 12; // 初始化静态变量
StaticMem.disp(); // 调用静态方法
访问修饰符:
class Encapsulate {
str1: string = "hello";
private str2: string = "world";
}
let obj = new Encapsulate();
console.log(obj.str1); // 可访问
console.log(obj.str2); // 编译错误,str2 是私有的
类实现接口:
interface ILoan {
interest: number
}
class AgriLoan implements ILoan {
interest: number;
rebate: number;
constructor(interest: number, rebate: number) {
this.interest = interest;
this.rebate = rebate;
}
}
let obj = new AgriLoan(10, 1);
命名空间一个最明确的目的就是解决重名问题。
namespace SomeNameSpaceName {
export interface ISomeInterfaceName { }
export class SomeClassName { }
}
以上定义了一个命名空间 SomeNameSpaceName,如果我们需要在外部可以调用 SomeNameSpaceName 中的类和接口,则需要在类和接口添加 export 关键字。调用方法如:SomeNameSpaceName.SomeClassName;
如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它,语法格式如下:
///
IShape.ts 文件:
namespace Drawing {
export interface IShape {
draw();
}
}
Circle.ts 文件:
///
namespace Drawing {
export class Circle implements IShape {
public draw() {
console.log("Circle is drawn");
}
}
}
Triangle.ts 文件:
///
namespace Drawing {
export class Triangle implements IShape {
public draw() {
console.log("Triangle is drawn");
}
}
}
TestShape.ts 文件:
///
///
///
function drawAllShapes(shape: Drawing.IShape) {
shape.draw();
}
drawAllShapes(new Drawing.Circle());
drawAllShapes(new Drawing.Triangle());
Invoice.ts 文件:
namespace Runoob {
export namespace invoiceApp {
export class Invoice {
public calculateDiscount(price: number) {
return price * .40;
}
}
}
}
InvoiceTest.ts 文件:
///
let invoice = new Runoob.invoiceApp.Invoice();
console.log(invoice.calculateDiscount(500));
我们可以使用 type 用来定义类型变量:
// 基本类型
type UserName = string
// 类型赋值
type WebSite = string | undefined
type Tsaid = WebSite
// 对象
type User = {
name: string;
age: number;
website: WebSite;
}
// 方法
type say = (age: number) => string
// 类型遍历 in
type ChinaMobilePhones = '10086' | '10010' | '10000'
type ChinaMobile {
name: string;
website: string;
}
type ChinaMobileList = {
[phone in ChinaMobilePhones]: ChinaMobile
}
当然,我们也可以使用 interface 定义我们的复杂类型,在 TypeScript 中我们也可以直接定义 interface:
interface Application {
init(): void
get(key: string): object
}
interface 和 type 很像。但是 type 的含义是定义自定义类型,当 TypeScript 提供给你的基础类型都不满足的时候,可以使用 type 自由组合出你的新类型,而 interface 应该是对外输出的接口。type 不可以被继承,但 interface 可以。