TypeScript 学习笔记

TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript。

TypeScript 通过类型注解提供编译时的静态类型检查。

TypeScript 是一种面向对象的编程语言。

1:TypeScript 基础类型

TypeScript 包含的数据类型
数据类型 关键字 描述
任意类型 any

声明为 any 的变量可以赋予任意类型的值

任意值是 TypeScript 针对编程时类型不明确的变量使用的一种数据类型,它常用于:

1、变量的值会动态改变时,比如来自用户的输入,任意值类型可以让这些变量跳过编译阶段的类型检查。

 2、定义存储各种类型数据的数组:let arrayList: any[] = [1, false, 'fine']

数字类型 number

双精度 64 位浮点值。它可以用来表示整数和分数。

let binaryLiteral: number = 0b1010; // 二进制
let octalLiteral: number = 0o744;    // 八进制
let decLiteral: number = 6;    // 十进制
let hexLiteral: number = 0xf00d;    // 十六进制
字符串类型 string

一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式。

let name: string = "Runoob";
let years: number = 5;
let words: string = `您好,今年是 ${ name } 发布 ${ years + 1} 周年`;
布尔类型 boolean

表示逻辑值:true 和 false。

let flag: boolean = true;
数组类型

声明变量为数组。

// 在元素类型后面加上[]
let arr: number[] = [1, 2];
// 或者使用数组泛型
let arr: Array = [1, 2];

多维数组: var arr_name:datatype[][]=[ [val1,val2,val3],[v1,v2,v3] ]

元组

元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。

let x: [string, number]; //指明元素类型
x = ['Runoob', 1];    // 赋值 ok 
x = [1, 'Runoob'];    //赋值 error 
console.log(x[0]);    // 输出 Runoob

元组中允许存储不同类型的元素,而数组只能存储相同类型的元素(any[] 类型的数组可以不同)。

枚举 enum

枚举类型用于定义数值集合。

enum Color {Red, Green, Blue};
let c: Color = Color.Blue;
console.log(c);    // 输出 2
void void

用于标识方法返回值的类型,表示该方法没有返回值

function hello(): void {
    alert("Hello Runoob");
}
null null

表示对象值缺失。

在 JavaScript 中 null 表示 "什么都没有"。

null是一个只有一个值的特殊类型。表示一个空对象引用。

用 typeof 检测 null 返回是 object。

undefined undefined

用于初始化变量为一个未定义的值。

在 JavaScript 中, undefined 是一个没有设置值的变量。

typeof 一个没有值的变量会返回 undefined。

never never never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。

注意:N

注意:Null 和 Undefined 是其他任何类型(包括 void)的子类型,可以赋值给其它类型,赋值后的类型会变成 null 或 undefined。

而在TypeScript中启用严格的空校验(--strictNullChecks)特性,就可以使得null 和 undefined 只能被赋值给 void 或本身对应的类型。

// 启用 --strictNullChecks
let x: number;
x = 1; // 编译正确
x = undefined;    // 编译错误
x = null;    // 编译错误

2:TypeScript 变量声明

变量使用前必须先声明。

声明变量的类型及初始值:var [变量名]  :  [类型] = 值 ;

声明变量的类型,但没有初始值,变量值会设置为 undefined:var [变量名]  :  [类型] ;

声明变量并初始值,但不设置类型,该变量可以是任意类型:var [变量名] = 值 ;

声明变量没有设置类型和初始值,类型可以是任意类型,默认初始值为 undefined: var [变量名] ;

2.1:类型断言(Type Assertion)

类型断言允许手动指定一个值的类型,即允许变量从一种类型更改为另一种类型<类型>值    或:  值 as 类型

2.2:类型推断

类型没有给出时,TypeScript 编译器利用类型推断来推断类型。如果不能推断出类型,那么它的类型将被视作为默认动态 any 类型。

var num = 2;    // 类型推断为 number
num = "12";    //编译错误 ,因为变量已经设置为了 number 类型

2.3:变量作用域

TypeScript 有以下几种作用域:

  • 全局作用域 − 全局变量定义在程序结构的外部,它可以在你代码的任何位置使用。

  • 类作用域 − 这个变量也可以称为 字段。类变量声明在一个类里头,但在类的方法外面。 该变量可以通过类的对象来访问。类变量也可以是静态的,静态的变量可以通过类名直接访问。

  • 局部作用域 − 局部变量,局部变量只能在声明它的一个代码块(如:方法)中使用。

var global_num = 12          // 全局变量
class Numbers { 
   num_val = 13;             // 实例变量//->类的对象访问
   static sval = 10;         // 静态变量  ->类名访问
   
   storeNum():void { 
      var local_num = 14;    // 局部变量  -> 代码块内访问
   } 
} 
console.log("全局变量为: "+global_num)  

console.log(Numbers.sval)   // 静态变量

var obj = new Numbers(); 
console.log("实例变量: "+obj.num_val)

3:TypeScript 运算符

3.1:类型运算符

typeof :返回操作数的数据类型。

var num = 12 
console.log(typeof num);   //输出结果: number

instanceof:用于判断对象是否为指定的类。

class Person{ } 
var obj = new Person() 
var isPerson = obj instanceof Person;  //true

4:TypeScript 循环

TypeScript 还支持 for…of 、forEach、every 和 some 循环。

for...of 语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for...of 循环,以替代 for...in 和 forEach() 。

可使用 every some 来取代 forEach。

// forEach 循环
let list = [4, 5, 6];
list.forEach((val, idx, array) => {
    // val: 当前值
    // idx:当前index
    // array: Array
});

// every 循环
let list = [4, 5, 6];
list.every((val, idx, array) => {
    // val: 当前值
    // idx:当前index
    // array: Array
    return true; // Continues
    // Return false will quit the iteration
});

while 语句在给定条件为 true 时,重复执行语句或语句组。循环主体执行之前会先测试条件。

while(condition)//当条件为 true 时执行循环。 当条件为 false 时,程序流将退出循环。
{
   statement(s);
}

do...while 循环是在循环的尾部检查它的条件。

do
{
   statement(s);
}while( condition ); /*条件表达式出现在循环的尾部,所以循环中的 statement(s) 会在条件被测试之前至少执行一次。 
如果条件为 true,控制流会跳转回上面的 do,然后重新执行循环中的 statement(s)。这个过程会不断重复,直到给定条件变为 false 为止。*/

break :强制终止循环,有两种用法:

  1. 当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
  2. 它可用于终止 switch 语句中的一个 case。

如果您使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。

continue 语句有点像 break 语句。但它不是强制终止,continue 会跳过当前循环中的代码,强迫开始下一次循环

对于 for 循环,continue 语句执行后,自增语句仍然会执行。对于 while 和 do...while 循环,continue 语句重新执行条件判断语句。

5:TypeScript 函数 (关键词 function)

函数是一组一起执行一个任务的语句。函数只有通过调用才可以执行函数内的代码。

函数声明告诉编译器函数的名称、返回类型和参数。

函数定义提供了函数的实际主体。

function function_name(param1 : datatype, param2 : datatype) :return_type {
 // 语句 
}

返回值的类型,需要与函数定义的返回类型(return_type)一致。

// 函数定义
function greet():string { // 返回一个字符串
    return "Hello World" 
} 
 
function caller() { 
    var msg = greet() // 调用 greet() 函数 
    console.log(msg) 
} 
 
// 调用函数
caller()

5.1:可选参数 ?

在 TypeScript 函数里,如果我们定义了参数,则我们必须传入这些参数,除非将这些参数设置为可选,可选参数使用问号标识 ?

可选参数必须跟在必需参数后面。

function function_name(param1:type,param2: type) { 
}

5.2:默认参数

设置参数的默认值,这样在调用函数的时候,如果不传入该参数的值,则使用默认参数。

function function_name(param1:type,param2:type = default_value) { 
}

注意:参数不能同时设置为可选和默认。

5.3:剩余参数

有时候,我们不知道要向函数传入多少个参数,这时候我们就可以使用剩余参数来定义。

剩余参数语法,允许我们将一个不确定数量的参数作为一个数组传入。

以 ... 为前缀,索引值从0(包括)开始。

function buildName(firstName: string, ...restOfName: string[]) {
}

5.4:匿名函数自调用

匿名函数自调用在函数后使用 () 即可:

(function(){
    alert(1)
})()

5.5:构造函数

TypeScript 支持使用 JavaScript 内置的构造函数 Function() 来定义函数:

var res = new Function (arg1, arg2, functionBody)

5.6:箭头函数 () => {}

函数体只有一行语句param1 :type, param2 :type ) => statement;

var foo = (x:number)=>10 + x  //函数体只有一条语句时,可省略关键字 return

console.log(foo(100))      //输出结果为 110

函数体是一个语句块 param1:type, param2:type ) => {  // 代码块  }

var foo = (x:number)=> {    
    x = 10 + x 
    console.log(x)  
} 
foo(100)

5.7:函数重载

重载是方法名字相同,而参数不同(类型、数量和顺序不同),返回类型可以相同也可以不同。

  • 如果参数类型不同,则参数类型应设置为 any
  • 参数数量不同你可以将不同的参数设置为可选。

定义函数重载需要定义重载签名和一个实现签名

重载签名定义函数的形参和返回类型,没有函数体。一个函数可以有多个重载签名(不可调用)

let suits = ["hearts", "spades", "clubs", "diamonds"];
// 定义重载签名 (不可调用)
function greet(person: string): string;
function greet(persons: string[]): string[];
// 定义实现签名 (可调用)
function greet(person: unknown): unknown {
    if (typeof person === 'string') {
        return `Hello, ${person}!`;
    } else if (Array.isArray(person)) {
        return person.map(name => `Hello, ${name}!`);
    }
    throw new Error('Unable to greet');
}
console.log(greet(suits[0]));
console.log(greet(suits));

6:数组解构

可以把数组元素值赋给变量。

var arr:number[] = [12,13] 
var [x,y] = arr // 将数组的两个元素值 赋给变量 x 和 y

console.log(x)  //12 ->相当于访问 arr[0]
console.log(y) //13->相当于访问 arr[1]

7:TypeScript Map 对象

Map 对象保存键值对,并且能够记住键的原始插入顺序。

任何值(对象或者原始值) 都可以作为一个键或一个值。

let myMap = new Map();

初始化 Map,可以以数组的格式来传入键值对:

let myMap = new Map( [
        ["key1", "value1"],
        ["key2", "value2"]
    ] ); 
// 迭代 Map 中的 key => value
for (let entry of nameSiteMapping.entries()) {
    console.log(entry[0], entry[1]);   
}
 
// 使用对象解析
for (let [key, value] of nameSiteMapping) {
    console.log(key, value);            
}
map.clear() 移除 Map 对象的所有键/值对 。
map.set()

设置键值对,返回该 Map 对象。

map.set("Google", 1);

map.get() 

返回键对应的值,如果不存在,则返回 undefined。

map.get("Google")//1

map.has()

返回一个布尔值,用于判断 Map 中是否包含键对应的值。

map.has("Taobao")//false

map.delete() 删除 Map 中的元素,删除成功返回 true,失败返回 false。
map.size 返回 Map 对象键/值对的数量。
map.keys()

返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。

map.values()  返回一个新的Iterator对象,包含了Map对象中每个元素的值 。

8:TypeScript 联合类型 |

联合类型(Union Types)可以通过管道()将变量设置多种类型:Type1 | Type2 | Type3

9:TypeScript 接口

接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法:interface interface_name { }

interface IPerson { 
    firstName:string, 
    lastName:string, 
    sayHi: ()=>string 
} 

var customer:IPerson = { //定义了一个变量 customer,它的类型是 IPerson
    firstName:"Tom",//customer 实现了接口 IPerson 的属性和方法。
    lastName:"Hanks", 
    sayHi: ():string =>{return "Hi there"} 
} 
 
console.log("Customer 对象") 
console.log(customer.firstName) 
console.log(customer.lastName) 
console.log(customer.sayHi())  

9.1:接口继承

接口继承就是说接口可以通过其它接口来扩展自己

继承使用关键字 extends。

单接口继承语法格式:Child_interface_name  extends  super_interface_name

多接口继承语法格式:Child_interface_name extends super_interface1_name ,  super_interface2_name

//单接口继承
interface Person { 
   age:number 
}  
interface Musician extends Person { 
   instrument:string 
}  

var drummer = {}; //断言为Musician类型
drummer.age = 27 //实现 Person 接口成员
drummer.instrument = "Drums" //实现 Musician 接口成员


//多接口继承
interface IParent1 { 
    v1:number 
} 
interface IParent2 { 
    v2:number 
} 
 
interface Child extends IParent1, IParent2 { } 
var Iobj:Child = { v1:12, v2:23 } 

9.2:接口与函数

interface IPoint { //定义接口IPoint 
    x:number 
    y:number 
} 
function addPoints(p1:IPoint,p2:IPoint):IPoint { //接口IPoint 作为函数参数类型
    var x = p1.x + p2.x 
    var y = p1.y + p2.y 

    return {x:x,y:y} 
} 
 
// 正确
var newPoint = addPoints({x:3,y:4},{x:5,y:1})  
 
// 错误 
var newPoint2 = addPoints({x:1},{x:4,y:3})

10:TypeScript 类

类描述了所创建的对象共同的属性和方法。

class class_name { 
    // 类作用域
}

类可以包含以下几个模块(类的数据成员):

  • 字段 − 字段是类里面声明的变量。字段表示对象的有关数据。

  • 构造函数 − 类实例化时调用,可以为类的对象分配内存。

  • 方法 − 方法为对象要执行的操作。

class Greeter {//声明了Greeter类
    greeting: string; // 包含成员:属性
    constructor(message: string) {//包含成员:构造函数(这个函数会在我们使用 new创建类实例的时候被调用)
        this.greeting = message;// this表示我们访问的是类的成员
    }
    greet() {//包含成员:方法
        return "Hello, " + this.greeting;
    }
}

let g = new Greeter("world");/*使用 new 关键字来实例化类的对象,new会调用构造函数.
创建一个 Greeter类型的新对象,并执行构造函数初始化它*/

g.greeting;// 通过对象,访问类属性
g.greet();// 通过对象,访问类方法

10.1:类的继承

在创建类的时候继承一个已存在的类,这个已存在的类称为父类,继承它的类称为子类

子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。

类继承使用关键字 extends:class child_class_name  extends  parent_class_name

class Shape { //创建了 Shape 类
   Area:number 
   
   constructor(a:number) { 
      this.Area = a 
   } 
} 
 
class Circle extends Shape { //Circle 类继承了 Shape 类
   disp():void { 
      console.log("圆的面积:  "+this.Area)  //Circle 类可以直接使用 Area 属性
   } 
}
  
var obj = new Circle(223); 
obj.disp()

10.2:多重继承

子类只能继承一个父类,TypeScript 不支持继承多个类,但支持多重继承。

class root{
  str1:string = "Hi";
}

class c1 extends root{//继承了 Root 类
 str2:string = "Hello";
};

class c2 extends c1{}; // 继承了 c1 和 Root 类 (多重继承,同时拥有  c1 和 Root 类的成员)

let obj = new c2();
alert(obj.str1) //通过 c2对象 ,访问root 属性
alert(obj.str2) //通过 c2对象 ,访问c1 属性

10.3:继承类的方法重写

类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。

super 关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。

class PrinterClass { 
   doPrint():void {
    ... //父类实体
   } 
} 
 
class StringPrinter extends PrinterClass { 
   doPrint():void { 
      super.doPrint() // 调用父类的doPrint函数

      ... //子类实体
   } 
}

10.4:static 关键字

static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用

class StaticMem {  
   static num:number; 
   
   static disp():void { 
      console.log("num 值为 "+ StaticMem.num) 
   } 

} 
StaticMem.num = 12     // 通过类名 StaticMem  ,初始化静态变量
StaticMem.disp()       // 通过类名 StaticMem  ,调用静态方法

10.5:访问控制修饰符

通过使用访问控制符来保护对类、变量、方法和构造方法的访问

TypeScript 支持 3 种不同的访问权限。

  • public(默认) : 公有,可以在任何地方被访问。

  • protected : 受保护,可以被其自身以及其子类访问。

  • private : 私有,只能被其定义所在的类访问。

10.6:类和接口

类可以实现接口,使用关键字 implements

interface ILoan { 
   interest:number 
} 
 
class AgriLoan implements ILoan {  //使用 关键字implements ,让AgriLoan 类实现了 ILoan 接口
   interest:number //实现接口ILoan 的interest成员
   rebate:number 
   
   constructor(interest:number,rebate:number) { //将 interest 字段作为AgriLoan类的属性使用
      this.interest = interest 
      this.rebate = rebate 
   } 
} 
 
var obj = new AgriLoan(10,1) 
console.log("利润为 : "+obj.interest+",抽成为 : "+obj.rebate )

11:TypeScript 对象

对象是包含一组键值对的实例。 值可以是标量、函数、数组、对象等

var sites = { 
   site1:"Runoob", 
   site2:"Google" 
};
sites.sayHello = function(){ return "hello";}//在对象中添加没有被定义的方法,报错

//修改为,则正常
var sites = {
    site1: "Runoob",
    site2: "Google",
    sayHello: function () { } // 类型模板 ->在Typescript 中的对象必须是特定类型的实例。
};
sites.sayHello = function () {
    console.log("hello " + sites.site1);
};
sites.sayHello();

12:TypeScript 模块

模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。然后,必须通过 import 导入其它模块导出的变量、函数、类等。

两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。

模块导出使用关键字 export 关键字:

你可能感兴趣的:(typescript,学习,笔记)