TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript。
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 多维数组: 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; // 编译错误
变量使用前必须先声明。
声明变量的类型及初始值:var [变量名] : [类型] = 值 ;
声明变量的类型,但没有初始值,变量值会设置为 undefined:var [变量名] : [类型] ;
声明变量并初始值,但不设置类型,该变量可以是任意类型:var [变量名] = 值 ;
声明变量没有设置类型和初始值,类型可以是任意类型,默认初始值为 undefined: var [变量名] ;
类型断言允许手动指定一个值的类型,即允许变量从一种类型更改为另一种类型:<类型>值 或: 值 as 类型
当类型没有给出时,TypeScript 编译器利用类型推断来推断类型。如果不能推断出类型,那么它的类型将被视作为默认动态 any 类型。
var num = 2; // 类型推断为 number
num = "12"; //编译错误 ,因为变量已经设置为了 number 类型
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)
typeof :返回操作数的数据类型。
var num = 12
console.log(typeof num); //输出结果: number
instanceof:用于判断对象是否为指定的类。
class Person{ }
var obj = new Person()
var isPerson = obj instanceof Person; //true
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 :强制终止循环,有两种用法:
如果您使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。
continue 语句有点像 break 语句。但它不是强制终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。
对于 for 循环,continue 语句执行后,自增语句仍然会执行。对于 while 和 do...while 循环,continue 语句重新执行条件判断语句。
函数是一组一起执行一个任务的语句。函数只有通过调用才可以执行函数内的代码。
函数声明告诉编译器函数的名称、返回类型和参数。
函数定义提供了函数的实际主体。
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()
在 TypeScript 函数里,如果我们定义了参数,则我们必须传入这些参数,除非将这些参数设置为可选,可选参数使用问号标识 ?。
可选参数必须跟在必需参数后面。
function function_name(param1:type,param2? : type) {
}
设置参数的默认值,这样在调用函数的时候,如果不传入该参数的值,则使用默认参数。
function function_name(param1:type,param2:type = default_value) {
}
注意:参数不能同时设置为可选和默认。
有时候,我们不知道要向函数传入多少个参数,这时候我们就可以使用剩余参数来定义。
剩余参数语法,允许我们将一个不确定数量的参数作为一个数组传入。
以 ... 为前缀,索引值从0(包括)开始。
function buildName(firstName: string, ...restOfName: string[]) {
}
匿名函数自调用在函数后使用 () 即可:
(function(){
alert(1)
})()
TypeScript 支持使用 JavaScript 内置的构造函数 Function() 来定义函数:
var res = new Function (arg1, arg2, functionBody)
函数体只有一行语句:( 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)
重载是方法名字相同,而参数不同(类型、数量和顺序不同),返回类型可以相同也可以不同。
定义函数重载需要定义重载签名和一个实现签名。
重载签名定义函数的形参和返回类型,没有函数体。一个函数可以有多个重载签名(不可调用)
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));
可以把数组元素值赋给变量。
var arr:number[] = [12,13]
var [x,y] = arr // 将数组的两个元素值 赋给变量 x 和 y
console.log(x) //12 ->相当于访问 arr[0]
console.log(y) //13->相当于访问 arr[1]
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对象中每个元素的值 。 |
联合类型(Union Types)可以通过管道( | )将变量设置多种类型:Type1 | Type2 | Type3
接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法: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())
接口继承就是说接口可以通过其它接口来扩展自己。
继承使用关键字 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 }
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})
类描述了所创建的对象共同的属性和方法。
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();// 通过对象,访问类方法
在创建类的时候继承一个已存在的类,这个已存在的类称为父类,继承它的类称为子类。
子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。
类继承使用关键字 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()
子类只能继承一个父类,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 属性
类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。
super 关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。
class PrinterClass {
doPrint():void {
... //父类实体
}
}
class StringPrinter extends PrinterClass {
doPrint():void {
super.doPrint() // 调用父类的doPrint函数
... //子类实体
}
}
static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。
class StaticMem {
static num:number;
static disp():void {
console.log("num 值为 "+ StaticMem.num)
}
}
StaticMem.num = 12 // 通过类名 StaticMem ,初始化静态变量
StaticMem.disp() // 通过类名 StaticMem ,调用静态方法
通过使用访问控制符来保护对类、变量、方法和构造方法的访问。
TypeScript 支持 3 种不同的访问权限。
public(默认) : 公有,可以在任何地方被访问。
protected : 受保护,可以被其自身以及其子类访问。
private : 私有,只能被其定义所在的类访问。
类可以实现接口,使用关键字 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 )
对象是包含一组键值对的实例。 值可以是标量、函数、数组、对象等
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();
模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。然后,必须通过 import 导入其它模块导出的变量、函数、类等。
两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。
模块导出使用关键字 export 关键字: