- Hi,Typescript啊啊啊,我来啦
- TypeScript 基础语法
- TypeScript 与面向对象
- 数据类型
- TypeScript 变量声明
- 类型断言(Type Assertion)
- 类型推断
- 变量作用域
- TypeScript 运算符
- TypeScript if条件语句
- switch…case 语句
- TypeScript 循环
- for 循环
- for…in 循环
- for…of 、forEach、every 和 some 循环
- while 循环
- do…while 循环
- TypeScript 函数
- 带参数函数
- 可选参数和默认参数
- 默认参数
- 剩余参数
- 匿名函数
- 构造函数
- 递归函数
- Lambda 函数(箭头函数)
- 函数重载
- TypeScript Number
- prototype
- TypeScript Array(数组)
- 数组解构
- 数组迭代
- 多维数组
- 数组方法
- TypeScript 元组
- 解构元组
- TypeScript 联合类型
- 联合类型数组
- TypeScript 接口
- 联合类型和接口
- 接口和数组
- 接口继承
- 单接口继承语法格式及🌰
- 多接口继承语法格式:
- 多继承实例🌰
- TypeScript 类
- 创建类的数据成员
- 创建实例化对象
- 完整实例
- 类的继承
- 继承类的方法重写
- static 关键字
- instanceof 运算符
- 访问控制修饰符
- 类和接口
- TypeScript 对象
- 此外对象也可以作为一个参数传递给函数,如下实例:
- 鸭子类型(Duck Typing)
- TypeScript 命名空间
- 嵌套命名空间
- TypeScript 模块
- 举个🌰
- TypeScript 声明文件
- 声明文件
Hi,Typescript啊啊啊,我来啦
Javascript是弱类型语言,而TypeScript 遵循强类型,如果将不同的类型赋值给变量会编译错误
如:var num:number = “hello” // 编译错误
TypeScript 基础语法
包括以下:模块。函数、变量、语句表达式、注释
const hello : string = “Hello World!”
console.log(hello)
ypeScript 区分大小写,分号可选:如果语句写在同一行则一定需要使用分号来分隔,否则会报错
TypeScript 与面向对象
面向对象主要有两个概念:对象和类。
- 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 类:类是一个模板,它描述一类对象的行为和状态。
- 方法:方法是类的操作的实现步骤。
TypeScript 面向对象编程实例:
class Site {name():void {console.log("Runoob")}}var obj = new Site();obj.name();-----<!-- 编译后生成的 JavaScript 代码如下: -->var Site = /** @class */ (function () {function Site() {}Site.prototype.name = function () {console.log("Runoob");};return Site;}());var obj = new Site();obj.name();
数据类型
1.string
2.numbers
3.boolean
4.number[] or Array
5.元祖:元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。
表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同
let x: [string,number]
x= [‘ww’,3]
6.枚举:枚举用来定义数值集合
enum Color {Red, Green, Blue}
let c:Color = Color.Blue
console.log(c) // 2返回的是数据的下标
7:void 用于标识函数返回值的类型,表示该方法没有返回值
8:null 表示对象值缺失,是一个只有一个值的特殊类型。表示一个空对象引用,typeof null === object。
9:undefined 表示初始化一个未定义的值,在 JavaScript 中, undefined 是一个没有设置值的变量,typeof undefined === undefind
10:any 声明为 any 的变量可以赋予任意类型的值。
11:never never是null 和undefind的子类型,代表从来不会出现的值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环),示例代码如下:
let x: never;
let y: number;
// 运行错误,数字类型不能转为 never 类型
x = 123;
// 运行正确,never 类型可以赋值给 never类型
x = (()=>{ throw new Error('exception')})();
// 运行正确,never 类型可以赋值给 数字类型
y = (()=>{ throw new Error('exception')})();
// 返回值为 never 的函数可以是抛出异常的情况
function error(message: string): never {
throw new Error(message);
}
// 返回值为 never 的函数可以是无法被执行到的终止点的情况
function loop(): never {
while (true) {}
}
TypeScript 变量声明
变量是一种使用方便的占位符,用于引用计算机内存地址,用来存储数据的容器
var name: string =”wxxxx” //name为string类型
var name = “nnnn”; // 此时的name为any类型
类型断言(Type Assertion)
类型断言是指可以手动指定一个类型,允许变量从一个类型更改为另一个类型
<类型>值 or 值 as 类型
var str:number = ‘23333’ //str是 string 类型
类型推断
当类型没有给出的时候,TS编译器会推断出类型
如果由于缺乏声明而不能推断出类型,那么它的类型被视作默认的动态 any 类型。
var num = 2; // 变量未指定类型,但ts类型推断为 number
num=“333” //推断出num为数字类型,而将字符串赋值给num,所以编译错误
变量作用域
变量作用域指定了变量定义的位置
程序中变量的可用性由变量作用域决定。
TypeScript 有以下几种作用域:
- 全局作用域 − 全局变量定义在程序结构的外部,它可以在你代码的任何位置使用。
- 类作用域 − 这个变量也可以称为 字段。类变量声明在一个类里头,但在类的方法外面。 该变量可以通过类的对象来访问。类变量也可以是静态的,静态的变量可以通过类名直接访问。
- 局部作用域 − 局部变量,局部变量只能在声明它的一个代码块(如:方法)中使用。
var global_num = 12 // 全局变量
class Numbers {
num_val = 13; // 实例变量
static sval = 10; // 静态变量
storeNum():void {
var local_num = 14; // 局部变量
}
}
TypeScript 运算符
- 算术运算符 + - * / % ++ —
- 逻辑运算符 && || !
如:var res:boolean=!((avg>50)&&(percentage>80));
短路运算符(&& 与 ||) - 关系运算符 == != > < >= <=
- 按位运算符 略用处不多
- 赋值运算符 = += -= *= /=
- 三元/条件运算符 a===b ? true : false
- 字符串运算符 连接运算符 (+)
- 类型运算符 typeof instanceof
TypeScript if条件语句
var num:number = 5
if (num > 0) {
console.log("数字是正数")
}
switch…case 语句
一个 switch 语句允许测试一个变量等于多个值时的情况。每个值称为一个 case,且被测试的变量会对每个 switch case 进行检查。
var grade:string = "A";
switch(grade) {
case "A": {
console.log("优");
break;
}
case "B": {
console.log("良");
break;
}
case "C": {
console.log("及格");
break;
}
case "D": {
console.log("不及格");
break;
}
default: {
console.log("非法输入");
break;
}
}
ps: switch 中的变量必须和case值具有相同的数据类型,且必须是一个常量或字面量
当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到 break 语句为止。
当遇到 break 语句时,switch 终止,控制流将跳转到 switch 语句后的下一行。
不是每一个 case 都需要包含 break。如果 case 语句不包含 break,控制流将会 继续 后续的 case,直到遇到 break 为止。
TypeScript 循环
for 循环
for ( init; condition; increment ){
statement(s);
}
--
var num:number = 5;
var i:number;
var factorial = 1;
for(i = num;i>=1;i--) {
factorial *= i;
}
console.log(factorial)
for…in 循环
var j:any;
var n:any = "a b c"
for(j in n) {
console.log(n[j])
}
for…of 、forEach、every 和 some 循环
for…of 语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for…of 循环,以替代 for…in 和 forEach() ,并支持新的迭代协议。for…of 允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等。
let someArray = [1, "string", false];
for (let entry of someArray) {
console.log(entry); // 1, "string", false
}
while 循环
var num:number = 5;
var factorial:number = 1;
while(num >=1) {
factorial = factorial * num;
num--;
}
console.log("5 的阶乘为:"+factorial);
do…while 循环
var n:number = 10;
do {
console.log(n);
n--;
} while(n>=0);
TypeScript 函数
function function_name():return_type {
// 语句
return value;
}
return_type 是返回值的类型。
return 关键词后跟着要返回的结果。
一个函数只能有一个 return 语句。
返回值的类型需要与函数定义的返回类型(return_type)一致。
// 函数定义
function greet():string { // 返回一个字符串
return "Hello World"
}
function caller() {
var msg = greet() // 调用 greet() 函数
console.log(msg)
}
// 调用函数
caller()
带参数函数
您可以向函数发送多个参数,每个参数使用逗号 , 分隔:
function func_name( param1 [:datatype], param2 [:datatype]) {
}
function add(x: number, y: number): number {
return x + y;
}
console.log(add(1,2))
可选参数和默认参数
在 TypeScript 函数里,如果我们定义了参数,则我们必须传入这些参数,除非将这些参数设置为可选,可选参数使用问号标识 ?
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // 错误,缺少参数
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,参数太多了
let result3 = buildName("Bob", "Adams"); // 正确
---
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // 正确
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,参数太多了
let result3 = buildName("Bob", "Adams"); // 正确
默认参数
function function_name(param1[:type],param2[:type] = default_value) {
}
注意:参数不能同时设置为可选和默认。
剩余参数
有一种情况,我们不知道要向函数传入多少个参数,这时候我们就可以使用剩余参数来定义。
剩余参数语法允许我们将一个不确定数量的参数作为一个数组传入。
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
匿名函数
匿名函数是一个没有函数名的函数。
匿名函数在程序运行时动态声明,除了没有函数名外,其他的与标准函数一样。
我们可以将匿名函数赋值给一个变量,这种表达式就成为函数表达式。
var res = function( [arguments] ) { … }
var res = function(a:number,b:number) {
return a*b;
};
console.log(res(12,2))
构造函数
TypeScript 也支持使用 JavaScript 内置的构造函数 Function() 来定义函数:
var res = new Function( [arguments] ) { ... })
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
递归函数
递归函数即在函数内调用函数本身。
function foo(number) {
if (number <= 0) { // 停止执行
return 1;
} else {
return (number * foo(number - 1)); // 调用自身
}
};
console.log(foo(6)); // 输出 720
Lambda 函数(箭头函数)
( [param1, parma2,…param n] )=>statement;
var foo = (x:number)=>10 + x
console.log(foo(100)) //输出结果为 110
我们可以不指定函数的参数类型,通过函数内来推断参数类型:
单个参数 () 是可选的
无参数时可以设置空括号
var func = (x)=> {
if(typeof x=="number") {
console.log(x+" 是一个数字")
} else if(typeof x=="string") {
console.log(x+" 是一个字符串")
}
}
func(12)
func("Tom")
函数重载
重载是方法名字相同,参数不同,返回类型可相同,也可不同
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表
function foo(a:number):void
function foo(a:string):void;
function foo(a:string |number):void
function foo(a:string,b:number):void
function foo)(b:number,a:number):void
如果参数类型不同,则参数类型应该设置为any
参数数量不同,可以将不同的参数设置为可选参数
function foo(x:any,y?:any):void {
console.log(x);
console.log(y);
}
foo(1,'2');
foo('www')
TypeScript Number
TypeScript 与 JavaScript 类似,支持 Number 对象。
prototype
prototype:Number 对象的静态属性。使您有能力向对象添加属性和方法。
constructor:返回对创建此对象的 Number 函数的引用。
function employee(id:number,name:string) {
this.id = id
this.name = name
}
var emp = new employee(123,"admin")
employee.prototype.email = "www@163.com"
TypeScript Array(数组)
var sites:string[];
sites = ["ww","xxx","nn"]
也可以在声明时直接初始化:
var sites: string[]=['xx','xx','22']
数组解构
var arr:number[]=[1,2]
var [x,y]=arr
---
编译成js
var arr = [1, 2];
var x = arr[0], y = arr[1]; // 将数组的两个元素赋值给变量 x 和 y
数组迭代
我们可以使用 for 语句来循环输出数组的各个元素:
var j:any;
var nums:number[] = [1001,1002,1003,1004]
for(j in nums) {
console.log(nums[j])
}
多维数组
var multi:number[][] = [[1,2,3],[23,24,25]]
数组方法
- concat()
连接两个或更多的数组,并返回结果
var a = ["a", "b", "c"];
var b = [1, 2, 3];
var c = a.concat(b);
console.log( c ); //["a", "b", "c", 1, 2, 3]
- every()
检测数值元素的每个元素是否都符合条件 - filter()
检测数值元素,并返回符合条件所有元素的数组。 - forEach()
数组每个元素都执行一次回调函数。 - indexOf()
搜索数组中的元素,并返回它所在的位置。
如果搜索不到,返回值 -1,代表没有此项。
- join()
把数组的所有元素放入一个字符串。 - lastIndexOf()
返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
var index = [12, 5, 8, 130, 44].lastIndexOf(8);
console.log(“index is : “ + index ); // 2
- map()
通过指定函数处理数组的每个元素,并返回处理后的数组。 - pop()
删除数组的最后一个元素并返回删除的元素。 - push()
向数组的末尾添加一个或更多元素,并返回新的长度。 - reduce()
将数组元素计算为一个值(从左到右)。
var total = [0, 1, 2, 3].reduce(function(a, b){ return a + b; });
console.log( total ); // 6 - reduceRight()
将数组元素计算为一个值(从右到左)。
var total = [0, 1, 2, 3].reduceRight(function(a, b){ return a + b; });
console.log( total ); // 6
- reverse()
反转数组的元素顺序。
var arr = [0, 1, 2, 3].reverse(); //[3,2,1,0] - shift()
删除并返回数组的第一个元素。
var arr = [10, 1, 2, 3].shift(); //10 - slice()
选取数组的的一部分,并返回一个新数组。
var arr = [“orange”, “mango”, “banana”, “sugar”, “tea”];
arr.slice( 1,2) //mango
arr.slice( 1,3)//“mango”, “banana” - some()
检测数组元素中是否有元素符合指定条件 - sort()
对数组的元素进行排序。 - splice()
从数组中添加或删除元素。
var arr = [“orange”, “mango”, “banana”, “sugar”, “tea”];
var removed = arr.splice(2, 0, “water”);//// orange,mango,water,banana,sugar,tea
var arr = [“orange”, “mango”, “banana”, “sugar”, “tea”];
arr.splice(3, 1); //[“sugar”]
arr // [“orange”, “mango”, “banana”, “tea”]
arr.toString() //“orange,mango,banana,tea”
- toString()
把数组转换为字符串,并返回结果。 - unshift()
向数组的开头添加一个或更多元素,并返回新的长度
var arr = [“orange”, “mango”, “banana”, “sugar”, “tea”];
arr.unshift(‘xxx’)
arr //[‘xxx’,”orange”, “mango”, “banana”, “sugar”, “tea”];
TypeScript 元组
数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组。
元组中允许存储不同类型的元素,元组可以作为参数传递给函数。
解构元组
var a =[10,”www”]
var [b,c] = a
TypeScript 联合类型
联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。
注意:只能赋值指定的类型,如果赋值其它类型就会报错。
创建联合类型的语法格式如下:Type1|Type2|Type3
联合类型数组
var arr:number[]|string[];
TypeScript 接口
接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方可通过这组抽象方法调用,让具体的类执行具体的方法
interface Istate{}
以下实例中,我们定义了一个接口 IPerson,接着定义了一个变量 customer,它的类型是 IPerson。
interface IPerson {
firstName:string,
lastName:string,
sayHi: ()=>string
}
var customer:IPerson = {
firstName:"Tom",
lastName:"Hanks",
sayHi: ():string =>{return "Hi there"}
}
需要注意接口不能转换为 JavaScript。 它只是 TypeScript 的一部分。
联合类型和接口
interface RunOptions {
program:string;
commandline:string[]|string|(()=>string);
}
//commandline是字符串
var options:RunOptions = {program:"test1",commandline:"Hello"};
//commandline是数组
options = {program:"test1",commandline:["Hello","World"]};
//commandline是函数
options = {program:"test1",commandline:()=>{return "**Hello World**";}};
接口和数组
接口中我们可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串。
interface Inamelist {
[index:number]:string
}
var list:Inamelist = ["John",1,"Bran"] / 错误元素 1 不是 string 类型
interface Iages {
[index:string]:number
}
var agelist:Iages;
agelist["John"] = 15 // 正确
agelist[2] = "nine" // 错误
接口继承
接口继承就是说接口可以通过其他接口来扩展自己。
Typescript 允许接口继承多个接口。
继承使用关键字 extends。
单接口继承语法格式及🌰
Child_interface_name extends super_interface_name
interface Person {
age:number
}
interface Musician extends Person {
instrument:string
}
var drummer = <Musician>{};
drummer.age = 27
drummer.instrument = "Drums"
编译后:
var drummer = {};
drummer.age = 27;
drummer.instrument = "Drums";
多接口继承语法格式:
Child_interface_name extends super_interface1_name, super_interface2_name,…,super_interfaceN_name
多继承实例🌰
interface IParent1 {
v1:number
}
interface IParent2 {
v2:number
}
interface Child extends IParent1, IParent2 { }
var obj:Child = { v1:12, v2:23}
编译后
var obj = { v1: 12, v2: 23 };
TypeScript 类
TypeScript 是面向对象的 JavaScript。
类描述了所创建的对象共同的属性和方法。
TypeScript 支持面向对象的所有特性,比如 类、接口等。
定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):
- 字段 − 字段是类里面声明的变量。字段表示对象的有关数据。
- 构造函数 − 类实例化时调用,可以为类的对象分配内存。
- 方法 − 方法为对象要执行的操作
举个栗子
class Person {
}
编译后:
var Person = /** @class */ (function () {
function Person() {
}
return Person;
}());
创建类的数据成员
以下实例我们声明了类 Car,包含字段为 engine,构造函数在类实例化后初始化字段 engine。
this 关键字表示当前类实例化的对象。注意构造函数的参数名与字段名相同,this.engine 表示类的字段。
此外我们也在类中定义了一个方法 disp()。
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
this.engine = engine
}
// 方法
disp():void {
console.log("发动机为 : "+this.engine)
}
}
编译后
var Car = /** @class */ (function () {
// 构造函数
function Car(engine) {
this.engine = engine;
}
// 方法
Car.prototype.disp = function () {
console.log("发动机为 : " + this.engine);
};
return Car;
}());
创建实例化对象
我们使用 new 关键字来实例化类的对象,语法格式如下:
var object_name = new class_name([ arguments ])
类实例化时会调用构造函数,例如:
var obj = new Car(“Engine 1”)
完整实例
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
this.engine = engine
}
// 方法
disp():void {
console.log(“函数中显示发动机型号 : “+this.engine)
}
}
// 创建一个对象
var obj = new Car(“XXSY1”)
// 访问字段
console.log(“读取发动机型号 : “+obj.engine)
// 访问方法
obj.disp()
类的继承
TypeScript 支持继承类,即我们可以在创建类的时候继承一个已存在的类,这个已存在的类称为父类,继承它的类称为子类。
类继承使用关键字 extends,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。
TypeScript 一次只能继承一个类,不支持继承多个类,但 TypeScript 支持多重继承(A 继承 B,B 继承 C)。
class child extends parent
需要注意的是子类只能继承一个父类,TypeScript 不支持继承多个类,但支持多重继承,如下实例:
class Root {
str:string;
}
class Child extends Root {}
class Leaf extends Child {} // 多重继承,继承了 Child 和 Root 类
var obj = new Leaf();
obj.str ="hello"
console.log(obj.str)
继承类的方法重写
类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。
其中 super 关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。
class PrinterClass {
doPrint():void {
console.log("父类的 doPrint() 方法。")
}
}
class StringPrinter extends PrinterClass {
doPrint():void {
super.doPrint() // 调用父类的函数
console.log("子类的 doPrint()方法。")
}
}
//父类的 doPrint() 方法。
//子类的 doPrint()方法。
static 关键字
static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。
class StaticMem {
static num:number;
static disp():void {
console.log("num 值为 "+ StaticMem.num)
}
}
StaticMem.num = 12 // 初始化静态变量
StaticMem.disp()
instanceof 运算符
instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。
class Person{ }
var obj = new Person()
var isPerson = obj instanceof Person;
console.log("obj 对象是 Person 类实例化来的吗? " + isPerson);
//obj 对象是 Person 类实例化来的吗? true
访问控制修饰符
TypeScript 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。
public(默认) : 公有,可以在任何地方被访问。
protected : 受保护,可以被其自身以及其子类和父类访问。
private : 私有,只能被其定义所在的类访问。
(类继承使用关键字 extends,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。)
class Encapsulate {
str1:string = "hello"
private str2:string = "world"
}
var obj = new Encapsulate()
console.log(obj.str1) // 可访问
console.log(obj.str2) // 编译错误, str2 是私有的
类和接口
类可以实现接口,使用关键字 implements,并将 interest 字段作为类的属性使用。
interface ILoan {
interest:number
}
class All implements ILoan {
a:number
b:number
constructor(a:number,b:number) {
this.a = a
this.b = a
}
}
var obj = new All(10,1)
//obj.a 10
//obj.b 1
TypeScript 对象
对象是包含一组键值对的实例。 值可以是标量、函数、数组、对象等,如下实例:
var object_name = {
key1: "value1", // 标量
key2: "value",
key3: function() {
// 函数
},
key4:["content1", "content2"] //集合
}
这时如果我们想在对象中添加方法,可以做以下修改:
js中:
var sites = {
site1:"ww",
site2:"nn"
};
sites.sayHello = function(){ return "hello";}
sites.sayHello();
//如果在 TypeScript 中使用以上方式则会出现编译错误,因为Typescript 中的对象必须是特定类型的实例。
ts中:
var sites = {
site1:"ww",
site2:"nn" ,
sayHello: function () { } // 类型模板
};
sites.sayHello = function(){ return "hello";}
sites.sayHello();
此外对象也可以作为一个参数传递给函数,如下实例:
var sites = {
site1:"www",
site2:"nnn",
};
var say = function(obj: { site1:string, site2 :string }) {
console.log("site1 :"+obj.site1)
console.log("site2 :"+obj.site2)
}
say(sites)
鸭子类型(Duck Typing)
鸭子类型(英语:duck typing)是动态类型的一种风格,是多态(polymorphism)的一种形式。
在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由”当前方法和属性的集合”决定。
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型。
interface IPoint {
x:number
y:number
}
function addPoints(p1:IPoint,p2: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})
TypeScript 命名空间
命名空间一个最明确的目的就是解决重名问题。
命名空间定义了标识符的可见范围,一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的。这样,在一个新的名字空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名字空间中。
namespace SomeNameSpaceName {
export interface ISomeInterfaceName { }
export class SomeClassName { }
}
//要在另外一个命名空间调用语法格式为:
SomeNameSpaceName.SomeClassName;
以上定义了一个命名空间 SomeNameSpaceName,如果我们需要在外部可以调用 SomeNameSpaceName 中的类和接口,则需要在类和接口添加 export 关键字。
IShape.ts 文件代码:
namespace Drawing {
export interface IShape {
draw();
}
}
----
Circle.ts 文件代码:
/// <reference path = "IShape.ts" />
namespace Drawing {
export class Circle implements IShape {
public draw() {
console.log("Circle is drawn");
}
}
}
----
Triangle.ts 文件代码:
/// <reference path = "IShape.ts" />
namespace Drawing {
export class Triangle implements IShape {
public draw() {
console.log("Triangle is drawn");
}
}
}
---
TestShape.ts 文件代码:
/// <reference path = "IShape.ts" />
/// <reference path = "Circle.ts" />
/// <reference path = "Triangle.ts" />
function drawAllShapes(shape:Drawing.IShape) {
shape.draw();
}
drawAllShapes(new Drawing.Circle());
drawAllShapes(new Drawing.Triangle());
嵌套命名空间
命名空间支持嵌套,可以把命名空间定义在另一个命名空间里
namespace namespace_name1 {
export namespace namespace_name2 {
export class class_name { }
}
}
成员的访问使用点号 . 来实现,如下实例:
Invoice.ts 文件代码:
namespace Istate {
export namespace invoiceApp {
export class Invoice {
public calculateDiscount(price: number) {
return price * .40;
}
}
}
}
InvoiceTest.ts 文件代码:
/// <reference path = "Invoice.ts" />
var invoice = new Istate.invoiceApp.Invoice();
console.log(invoice.calculateDiscount(500));
TypeScript 模块
TypeScript 模块的设计理念是可以更换的组织代码。
模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。类似地,我们必须通过 import 导入其他模块导出的变量、函数、类等。
两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。
模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于 Node.js 的 CommonJS 和服务于 Web 应用的 Require.js。
此外还有有 SystemJs 和 Webpack。
模块导出使用关键字 export 关键字,语法格式如下:
// 文件名 : SomeInterface.ts
export interface SomeInterface {
// 代码部分
}
要在另外一个文件使用该模块就需要使用 import 关键字来导入:
import someInterfaceRef = require(“./SomeInterface”);
举个🌰
IShape.ts 文件代码:
/// <reference path = "IShape.ts" />
export interface IShape {
draw();
}
Circle.ts 文件代码:
import shape = require("./IShape");
export class Circle implements shape.IShape {
public draw() {
console.log("Cirlce is drawn (external module)");
}
}
Triangle.ts 文件代码:
import shape = require("./IShape");
export class Triangle implements shape.IShape {
public draw() {
console.log("Triangle is drawn (external module)");
}
}
TestShape.ts 文件代码:
import shape = require("./IShape");
import circle = require("./Circle");
import triangle = require("./Triangle");
function drawAllShapes(shapeToDraw: shape.IShape) {
shapeToDraw.draw();
}
tsc --module amd TestShape.ts
TypeScript 声明文件
TypeScript 作为 JavaScript 的超集,在开发过程中不可避免要引用其他第三方的 JavaScript 的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript 诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了。
在 TypeScript 中,我们并不知道 $ 或 jQuery 是什么东西:
jQuery(‘#foo’);// index.ts(1,1): error TS2304: Cannot find name ‘jQuery’.
这时,我们需要使用 declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对:
declare var jQuery: (selector: string) => any;
jQuery(‘#foo’);
declare 定义的类型只会用于编译时的检查,编译结果中会被删除。
上例的编译结果是:jQuery(‘#foo’);
声明文件
声明文件以 .d.ts 为后缀,例如:aaa.d.ts
声明文件或模块的语法格式如下:
declare module Module_Name {
}
TypeScript 引入声明文件语法格式: ///
下定义一个第三方库来演示:
CalcThirdPartyJsLib.js 文件代码:
var Run;
(function(Run) {
var Calc = (function () {
function Calc() {
}
})
Calc.prototype.doSum = function (limit) {
var sum = 0;
for (var i = 0; i <= limit; i++) {
sum = sum + i;
}
return sum;
}
Run.Calc = Calc;
return Calc;
})(Run || (Run = {}));
var test = new Run.Calc();
如果我们想在 TypeScript 中引用上面的代码,则需要设置声明文件 Calc.d.ts,代码如下:
Calc.d.ts 文件代码:
declare module Run {
export class Calc {
doSum(limit:number) : number;
}
}
CalcTest.ts 文件代码:
/// <reference path = "Calc.d.ts" />
var obj = new Run.Calc();
// obj.doSum("Hello"); // 编译错误
console.log(obj.doSum(10));
