/**
var message:string = "Hello World"
console.log(message)
命名为Runoob.ts
以上代码首先通过 tsc 命令编译:
tsc Runoob.ts
得到如下 js 代码:
Runoob.js 文件代码:
var hello = "Hello World!";
console.log(hello);
最后我们使用 node 命令来执行该 js 代码。
$ node Runoob.js
Hello World
我们可以同时编译多个 ts 文件:
tsc file1.ts file2.ts file3.ts
*/
class Site {
name():void {
console.log("Runoob")
}
}
var obj = new Site();
obj.name();
let octalLiteral: number = 0o744; // 八进制
let name1: string = "Runoob";
let years: number = 5;
let words: string = `您好,今年是 ${ name1 } 发布 ${ years + 1} 周年`;
// 在元素类型后面加上[]
let arr: number[] = [1, 2];
// 或者使用数组泛型
let arr2: Array<number> = [1, 2];
//元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。
let x: [string, number];
x = ['Runoob', 1]; // 运行正常
//x = [1, 'Runoob']; // 报错
console.log(x[0]); // 输出 Runoob
//枚举类型用于定义数值集合。
enum Color {Red, Green, Blue};
let c: Color = Color.Blue;
console.log(c); // 输出 2
//void 用于标识方法返回值的类型,表示该方法没有返回值。
function hello(): void {
alert("Hello Runoob");
}
//改写现有代码时,任意值允许在编译时可选择地包含或移除类型检查,示例代码如下:
let xx: any = 4;
xx.ifItExists(); // 正确,ifItExists方法在运行时可能存在,但这里并不会检查
xx.toFixed(); // 正确
//定义存储各种类型数据的数组时,示例代码如下:
let arrayList: any[] = [1, false, 'fine'];
arrayList[1] = 100;
//Null 和 Undefined 是其他任何类型(包括 void)的子类型,可以赋值给其它类型,如数字类型.而在TypeScript中启用严格的空校验(--strictNullChecks)特性,就可以使得null 和 undefined 只能被赋值给 void 或本身对应的类型,示例代码如下:
// 启用 --strictNullChecks
let xy: number;
xy = 1; // 编译正确
//xy = undefined; // 编译错误
//xy = null; // 编译错误
/**
*
上面的例子中变量 x 只能是数字类型。如果一个类型可能出现 null 或 undefined, 可以用 | 来支持多种类型,示例代码如下:
// 启用 --strictNullChecks
let x: number | null | undefined;
x = 1; // 编译正确
x = undefined; // 编译正确
x = null; // 编译正确
*/
/**never 类型
never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环),示例代码如下:
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) {}
}
*/
// 带参数匿名函数:
// var res = function(a:number,b:number) {
// return a*b;
// };
// console.log(res(12,2))
//匿名函数自调用
(function () {
var x = "Hello!!";
console.log(x)
})()
/**
构造函数
TypeScript 也支持使用 JavaScript 内置的构造函数 Function() 来定义函数:
语法格式如下:
"return a * b" 代表一个含有包括函数定义的 JavaScript 语句的字符串。
**/
var myFunction = new Function("a", "b", "return a * b");
var p = myFunction(4, 3);
console.log(p);
//以下实例声明了 lambda 表达式函数,函数返回两个数的和:
var foo = (x:number)=>10 + x
console.log(foo(100)) //输出结果为 110
//搞这么花干啥
function add(x: number, y: number): number {
return x + y;
}
console.log(add(1,2))
//定义函数重载需要定义重载签名和一个实现签名。重载签名定义函数的形参和返回类型,没有函数体。一个函数可以有多个重载签名(不可调用)
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));
/* 或者这个 怎么感觉不定义重载签名也能运行
function disp(s1:string):void;
function disp(n1:number,s1:string):void;
function disp(x:any,y?:any):void {
console.log(x);
console.log(y);
}
disp("abc")
disp(1,"xyz");
*/
/*
replace()
替换与正则表达式匹配的子串
*/
var re = /(\w+)\s(\w+)/;
var str = "zara ali";
var newstr = str.replace(re, "$2, $1");
console.log(newstr); // ali, zara
//数组申明
var array_name2 : number[]; //声明
array_name2 = [1,2,3] //初始化
//直接申明数组
var numlist:number[] = [2,4,6,8]
var arr_names:number[] = new Array(4)
for(var i = 0; i<arr_names.length; i++) {
arr_names[i] = i * 2
console.log(arr_names[i])
}
var sites:string[] = new Array("Google","Runoob","Taobao","Facebook")
for(var i = 0;i<sites.length;i++) {
console.log(sites[i])
}
//数组元素赋值给变量
var arr3:number[] = [12,13]
var[x3,y3] = arr // 将数组的两个元素赋值给变量 x 和 y
console.log(x3)
console.log(y3)
//数组迭代
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]]
console.log(multi[0][0])
console.log(multi[0][1])
console.log(multi[0][2])
console.log(multi[1][0])
console.log(multi[1][1])
console.log(multi[1][2])
//数组作为参数传递给函数
var sites:string[] = new Array("Google","Runoob","Taobao","Facebook")
function disp(arr_sites:string[]) {
for(var i = 0;i<arr_sites.length;i++) {
console.log(arr_sites[i])
}
}
disp(sites);
//数组方法 删除数组的最后一个元素并返回删除的元素。
var numbers = [1, 4, 9];
var element = numbers.pop();
console.log("element is : " + element ); // 9
var element = numbers.pop();
console.log("element is : " + element ); // 4
//reduceRight() 将数组元素计算为一个值(从右到左)。
var total = [0, 1, 2, 3].reduceRight(function(a, b){ return a + b; });
console.log("total is : " + total ); // 6
//splice() 从数组中添加或删除元素。
var arr4 = ["orange", "mango", "banana", "sugar", "tea"];
var removed = arr4.splice(2, 0, "water");
console.log("After adding 1: " + arr4 ); // orange,mango,water,banana,sugar,tea
console.log("removed is: " + removed);
removed = arr4.splice(3, 1);
console.log("After removing 1: " + arr4 ); // orange,mango,water,sugar,tea
console.log("removed is: " + removed); // banana
//map
let myMap = new Map();
let myMap2 = new Map([
["key1", "value1"],
["key2", "value2"]
]);
let nameSiteMapping = new Map();
// 设置 Map 对象
nameSiteMapping.set("Google", 1);
nameSiteMapping.set("Runoob", 2);
nameSiteMapping.set("Taobao", 3);
// 获取键对应的值
console.log(nameSiteMapping.get("Runoob")); // 2
// 判断 Map 中是否包含键对应的值
console.log(nameSiteMapping.has("Taobao")); // true
console.log(nameSiteMapping.has("Zhihu")); // false
// 返回 Map 对象键/值对的数量
console.log(nameSiteMapping.size); // 3
// 删除 Runoob
console.log(nameSiteMapping.delete("Runoob")); // true
console.log(nameSiteMapping);
// 移除 Map 对象的所有键/值对
nameSiteMapping.clear(); // 清除 Map
console.log(nameSiteMapping);
//元祖
var mytuple22 = [10,"Runoob"];
mytuple22[0] = 120
mytuple22[1] = 234
//元组运算
var mytuple = [10,"Hello","World","typeScript"];
console.log("添加前元素个数:"+mytuple.length) // 返回元组的大小
mytuple.push(12) // 添加到元组中
console.log("添加后元素个数:"+mytuple.length)
console.log("删除前元素个数:"+mytuple.length)
console.log(mytuple.pop()+" 元素从元组中删除") // 删除并返回删除的元素
console.log("删除后元素个数:"+mytuple.length)
var a =[10,"Runoob"]
var [b,cc] = a
console.log( b )
console.log( cc )
/**
* TypeScript 联合类型
联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。
注意:只能赋值指定的类型,如果赋值其它类型就会报错。
*/
var val:string|number
val = 12
console.log("数字为 "+ val)
val = "Runoob"
console.log("字符串为 " + val)
var arr5:number[]|string[];
var i:number;
arr5 = [1,2,4]
console.log("**数字数组**")
for(i = 0;i<arr5.length;i++) {
console.log(arr5[i])
}
arr5 = ["Runoob","Google","Taobao"]
console.log("**字符串数组**")
for(i = 0;i<arr5.length;i++) {
console.log(arr5[i])
}
/**TypeScript 接口
接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。 */
interface IPerson {
firstName:string,
lastName:string,
sayHi: ()=>string
}
var customer:IPerson = {
firstName:"Tom",
lastName:"Hanks",
sayHi: ():string =>{return "Hi there"}
}
console.log("Customer 对象 ")
console.log(customer.firstName)
console.log(customer.lastName)
console.log(customer.sayHi())
var employee:IPerson = {
firstName:"Jim",
lastName:"Blakes",
sayHi: ():string =>{return "Hello!!!"}
}
console.log("Employee 对象 ")
console.log(employee.firstName)
console.log(employee.lastName)
//上述代码编译js后
var customer = {
firstName: "Tom",
lastName: "Hanks",
sayHi: function () { return "Hi there"; }
};
console.log("Customer 对象 ");
console.log(customer.firstName);
console.log(customer.lastName);
console.log(customer.sayHi());
var employee = {
firstName: "Jim",
lastName: "Blakes",
sayHi: function () { return "Hello!!!"; }
};
console.log("Employee 对象 ");
console.log(employee.firstName);
console.log(employee.lastName);
//接口继承
interface IParent1 {
v1:number
}
interface IParent2 {
v2:number
}
interface Child extends IParent1, IParent2 { }
var Iobj:Child = { v1:12, v2:23}
console.log("value 1: "+Iobj.v1+" value 2: "+Iobj.v2)
/*TypeScript 是面向对象的 JavaScript。
类描述了所创建的对象共同的属性和方法。
TypeScript 支持面向对象的所有特性,比如 类、接口等。
TypeScript 类定义方式如下:
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 Car2 = /** @class */ (function () {
// 构造函数
function Car2(engine) {
this.engine = engine;
}
// 方法
Car2.prototype.disp = function () {
console.log("发动机为 : " + this.engine);
};
return Car2;
}());
/**这段代码定义了一个名为Car2的类,它有一个构造函数和一个方法。其中:
构造函数Car2:接受一个参数engine,表示创建Car2对象时需要传入一个发动机型号。在构造函数内部,使用关键字this来指代当前对象,并将engine赋值给它的属性this.engine。
方法disp:不接受参数,用于打印出当前Car2对象的发动机型号。在方法内部,使用了模板字符串来拼接字符串和对象属性。
整段代码使用了ES6的class语法,并使用了注释指定了类的类型。
在JavaScript中,每个函数都有一个特殊的属性叫做prototype,它是一个对象,用于存储该函数所创建的对象的公共方法和属性。也就是说,通过prototype,我们可以让该函数创建的所有对象都拥有相同的方法和属性。
在上述代码中,Car2函数被定义为一个类,使用了class关键字。在类定义中,Car2.prototype指向该类的原型对象,而disp方法是在原型对象上定义的,因此所有Car2对象都可以共享该方法。
在JavaScript中,使用原型对象来共享方法和属性是一种非常常见的方式,这种方式可以避免每个对象都复制一遍相同的方法和属性,从而节省内存空间,提高代码效率。
*/
// 创建一个对象
var carInstance = new Car("XXSY1")
// 访问字段
console.log("读取发动机型号 : "+carInstance.engine)
// 访问方法
carInstance.disp()
/**类的继承:实例中创建了 Shape 类,Circle 类继承了 Shape 类,Circle 类可以直接使用 Area 属性: */
class Shape {
Area:number
constructor(a:number) {
this.Area = a
}
}
class Circle extends Shape {
disp():void {
console.log("圆的面积: "+this.Area)
}
}
var myCircle = new Circle(223);
myCircle.disp()
/**
编译以上代码,得到以下 JavaScript 代码:
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Shape = (function () {
function Shape(a) {
this.Area = a;
}
return Shape;
}());
var Circle = (function (_super) {
__extends(Circle, _super);
function Circle() {
return _super !== null && _super.apply(this, arguments) || this;
}
Circle.prototype.disp = function () {
console.log("圆的面积: " + this.Area);
};
return Circle;
}(Shape));
var 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() // 调用静态方法
//instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。
class Person2{ }
var obj2 = new Person()
var isPerson = obj2 instanceof Person;
console.log("obj 对象是 Person 类实例化来的吗? " + isPerson);
/**TypeScript 对象
对象是包含一组键值对的实例。 值可以是标量、函数、数组、对象等,如下实例: */
var object_name = {
key1: "value1", // 标量
key2: "value",
key3: function() {
// 函数
},
key4:["content1", "content2"] //集合
}
var MANYsites = {
site1:"Runoob",
site2:"Google"
};
// 访问对象的值
console.log(MANYsites.site1)
console.log(MANYsites.site2)
/**TypeScript 类型模板
假如我们在 JavaScript 定义了一个对象: */
var sites0 = {
site1:"Runoob",
site2:"Google"
};
//这时如果我们想在对象中添加方法,可以做以下修改:sites0.sayHello = function(){ return "hello";}
//如果在 TypeScript 中使用以上方式则会出现编译错误,因为Typescript 中的对象必须是特定类型的实例。
var sites00 = {
site1: "Runoob",
site2: "Google",
sayHello: function () { } // 类型模板
};
sites00.sayHello = function () {
console.log("hello " + sites00.site1);
};
sites00.sayHello();
/**
* 鸭子类型(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 命名空间
命名空间一个最明确的目的就是解决重名问题。
假设这样一种情况,当一个班上有两个名叫小明的学生时,为了明确区分它们,我们在使用名字之外,不得不使用一些额外的信息,比如他们的姓(王小明,李小明),或者他们父母的名字等等。
命名空间定义了标识符的可见范围,一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的。这样,在一个新的名字空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名字空间中。
TypeScript 中命名空间使用 namespace 来定义,语法格式如下:
*/
//IShape.ts 文件代码:
namespace Drawing {
export interface IShape {
draw();
}
}
//Circle.ts 文件代码:
///
namespace Drawing {
export class Circle implements IShape {
public draw() {
console.log("Circle is drawn");
}
}
}
//TestShape.ts 文件代码:
///
///
///
function drawAllShapes(shape:Drawing.IShape) {
shape.draw();
}
drawAllShapes(new Drawing.Circle());
//drawAllShapes(new Drawing.Triangle());
/***TypeScript 模块
TypeScript 模块的设计理念是可以更换的组织代码。
模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。类似地,我们必须通过 import 导入其他模块导出的变量、函数、类等。
两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。
模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于 Node.js 的 CommonJS 和服务于 Web 应用的 Require.js。
此外还有有 SystemJs 和 Webpack。 */
//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();
}
drawAllShapes(new circle.Circle());
drawAllShapes(new triangle.Triangle());
//使用 tsc 命令编译以上代码(AMD):tsc --module amd TestShape.ts
//使用 tsc 命令编译以上代码(Commonjs):tsc --module commonjs TestShape.ts
/**TypeScript 声明文件
TypeScript 作为 JavaScript 的超集,在开发过程中不可避免要引用其他第三方的 JavaScript 的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript 诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了。/
*/
/**
*
假如我们想使用第三方库,比如 jQuery,我们通常这样获取一个 id 是 foo 的元素:
$('#foo');
// 或
jQuery('#foo');
但是在 TypeScript 中,我们并不知道 $ 或 jQuery 是什么东西:
这时,我们需要使用 declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对:
declare var jQuery: (selector: string) => any;
jQuery('#foo');
声明文件以 .d.ts 为后缀,例如:
声明文件或模块的语法格式如下:
declare module Module_Name {
}
TypeScript 引入声明文件语法格式:
///
*/