与JS类似部分,本文不做说明(运算符、条件语句、循环语句、函数、基本类型等)
TypeScript
的设计目的应该是解决JavaScript的痛点
:弱类型和没有命名空间,导致很难模块化,不适合开发大型程序。另外它还提供了一些语法糖来帮助大家更方便地实践面向对象的编程。
TypeScript
并没有抛弃JavaScript
的语法另起炉灶,而是做成了JavaScript的超集,这样任何合法的JavaScript的语句在TypeScript下都是合法的,也就是说学习成本很低
语法糖:TypeScript
可以实现类,接口,枚举,泛型,方法重载等,用简洁的语法丰富了JavaScript
的使用。
类型检查:谷歌的Flow
也可以做到
ES6用类Class
(语法糖)也挺好用的啦…
TypeScript
TypeScript
实例//var [变量名] : [类型] = 值;
const hello : string = "Hello World!"
console.log(hello)
TypeScript
安装【即在cmd中将ts编译成js的命令】npm install -g typescript
//以下是查看版本号
$ tsc -v
Version 3.2.2
var message:string = "Hello World"
console.log(message)
tsc
命令将 TypeScript 转换为 JavaScript 代码:tsc test.ts
var message = "Hello World";
console.log(message);
$ node test.js
Hello World
tsc file1.ts, file2.ts, file3.ts
1. --help显示帮助信息
2. --module载入扩展模块
3. --target设置 ECMA 版本
4. --declaration额外生成一个 .d.ts 扩展名的文件。
tsc ts-hw.ts --declaration生成 ts-hw.d.ts、ts-hw.js 两个文件。
5. --removeComments删除文件的注释
6. --out编译多个文件并合并到一个输出的文件
7. --sourcemap生成一个 sourcemap (.map) 文件。sourcemap 是一个存储源代码与编译代码对应位置映射的信息文件。
8. --module noImplicitAny在表达式和声明上有隐含的 any 类型时报错
9. --watch在监视模式下运行编译器。会监视输出文件,在它们改变时重新编译。
TypeScript
元祖&联合类型var val:string|number
val = 12
console.log("数字为 "+ val)
val = "Runoob"
console.log("字符串为 " + val)
function disp(name:string|string[]) {
if(typeof name == "string") {
console.log(name)
} else {
var i;
for(i = 0;i
var arr:number[]|string[]
TypeScript
接口接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现
/**
TypeScript 接口定义如下
interface interface_name { }
以下实例中,我们定义了一个接口 IPerson,
接着定义了一个类型为IPerson变量 customer
customer 实现了接口 IPerson 的属性和方法。
注意接口不能转换为 JavaScript。
它只是 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())
interface RunOptions {
program:string;
commandline:string[]|string|(()=>string);
}
// commandline 是字符串
var options:RunOptions = {program:"test1",commandline:"Hello"};
console.log(options.commandline)
// commandline 是字符串数组
options = {program:"test1",commandline:["Hello","World"]};
console.log(options.commandline[0]);
console.log(options.commandline[1]);
// commandline 是一个函数表达式
options = {program:"test1",commandline:()=>{return "**Hello World**";}};
var fn:any = options.commandline;
console.log(fn());
/**
接口中可以将数组的索引值和元素设置为不同类型,
索引值可以是数字或字符串
*/
interface namelist {
[index:number]:string
}
// 错误元素 1: 不是 string 类型
var list2:namelist = ["John",1,"Bran"]
interface ages {
[index:string]:number
}
var agelist:ages;
agelist["John"] = 15 // 正确
agelist[2] = "nine" // 错误
/**
接口继承就是说接口可以通过其他接口来扩展自己。
Typescript 允许接口继承多个接口。
继承使用关键字 extends。
*/
//单接口继承语法格式:
Child_interface_name extends super_interface_name
//多接口继承语法格式:
Child_interface_name extends super_interface1_name,
super_interface2_name,…,super_interfaceN_name
//单继承实例
interface Person {
age:number
}
interface Musician extends Person {
instrument:string
}
var drummer = {};
drummer.age = 27
drummer.instrument = "Drums"
console.log("年龄: "+drummer.age)
console.log("喜欢的乐器: "+drummer.instrument)
//多继承实例
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
类类描述了所创建的对象共同的属性和方法。
//语法:class class_name { }
class Person {}
//编译成js就是:
var Person = /** @class */ (function () {
function Person() {
}
return Person;
}());
//创建类的数据成员
class Car {
engine:string; // 字段
constructor(engine:string) { // 构造函数
this.engine = engine
}
disp():void { // 方法
console.log("发动机为 : "+this.engine)
}
}
//创建实例
var obj = new Car("Engine 1")
obj.disp()
子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。
TypeScript
一次只能继承一个类,不支持继承多个类,但TypeScript
支持多重继承(A 继承 B,B 继承 C)。
//语法:class child_class_name extends parent_class_name
/**
下面实例中创建了 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 obj = new Circle(223);
obj.disp()
/**
类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。
其中super关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。
*/
class PrinterClass {
doPrint():void {
console.log("父类的 doPrint() 方法。")
}
}
class StringPrinter extends PrinterClass {
doPrint():void {
super.doPrint() // 调用父类的函数
console.log("子类的 doPrint()方法。")
}
}
static
关键字
static
关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。
class StaticMem {
static num:number;
static disp():void {
console.log("num 值为 "+ StaticMem.num)
}
}
StaticMem.num = 12 // 初始化静态变量
StaticMem.disp() // 调用静态方法
//上述代码编译成js就是
var StaticMem = /** @class */ (function () {
function StaticMem() {
}
StaticMem.disp = function () {
console.log("num 值为 " + StaticMem.num);
};
return StaticMem;
}());
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);
可以使用访问控制符来保护对类、变量、方法和构造方法的访问
/**
public(默认) : 公有,可以在任何地方被访问。
protected : 受保护,可以被其自身以及其子类和父类访问。
private : 私有,只能被其定义所在的类访问。
*/
class Encapsulate {
str1:string = "hello"
private str2:string = "world"
}
var obj = new Encapsulate()
console.log(obj.str1) // 可访问
console.log(obj.str2) // 编译错误, str2 是私有的
类可以实现接口,使用关键字
implements
interface ILoan {
interest:number
}
class AgriLoan implements ILoan {
interest:number
rebate:number
constructor(interest:number,rebate:number) {
this.interest = interest
this.rebate = rebate
}
}
var obj = new AgriLoan(10,1)
console.log("利润为 : "+obj.interest+",抽成为 : "+obj.rebate )
TypeScript
对象JavaScript
对象没啥区别/**
对象是包含一组键值对的实例。
值可以是标量、函数、数组、对象等,如下实例
*/
var object_name = {
key1: "value1", // 标量
key2: "value",
key3: function() {
// 函数
},
key4:["content1", "content2"] //集合
}
console.log(object_name.key1)
//假如我们在 JavaScript 定义了一个对象:
var sites = {
site1:"Runoob",
site2:"Google"
};
//这时如果我们想在对象中添加方法,可以做以下修改:
sites.sayHello = function(){ return "hello";}
//如果在 TypeScript 中使用以上方式则会出现编译错误,
//因为Typescript 中的对象必须是特定类型的实例。
--------------------------------------------------
//在typescript中得如下定义:
var sites = {
site1: "Runoob",
site2: "Google",
sayHello: function () { } // 类型模板
};
sites.sayHello = function () {
console.log("hello " + sites.site1);
};
sites.sayHello();
--------------------------------------------------
/**
鸭子类型(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
来定义//语法如下:
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());
使用 tsc 命令编译以上代码:
tsc --out app.js TestShape.ts
namespace namespace_name1 {
export namespace namespace_name2 {
export class class_name { }
}
}
//成员的访问使用点号 . 来实现,如下实例:
//Invoice.ts 文件代码:
namespace Runoob {
export namespace invoiceApp {
export class Invoice {
public calculateDiscount(price: number) {
return price * .40;
}
}
}
}
//InvoiceTest.ts 文件代码:
///
var invoice = new Runoob.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 文件代码:
///
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());
TypeScript
声明文件[declare
]TypeScript
作为 JavaScript
的超集,在开发过程中不可避免要引用其他第三方的 JavaScript
的库。TypeScript
诸如类型检查等特性功能。JavaScript
库和模块信息的声明文件。TypeScript
的各种特性来使用库文件了。假如我们想使用第三方库,比如 jQuery,
我们通常这样获取一个 id 是 foo 的元素:
$('#foo');
// 或
jQuery('#foo');
但是在 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 为后缀,例如:runoob.d.ts
声明文件或模块的语法格式如下:
declare module Module_Name {
}
TypeScript 引入声明文件语法格式:
///
当然,很多流行的第三方库的声明文件不需要我们定义了,
比如 jQuery 已经有人帮我们定义好了:
jQuery in DefinitelyTyped。
以下定义一个第三方库来演示:
CalcThirdPartyJsLib.js 文件代码:
var Runoob;
(function(Runoob) {
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;
}
Runoob.Calc = Calc;
return Calc;
})(Runoob || (Runoob = {}));
var test = new Runoob.Calc();
如果我们想在 TypeScript 中引用上面的代码,则需要设置声明文件 Calc.d.ts,代码如下:
Calc.d.ts 文件代码:
declare module Runoob {
export class Calc {
doSum(limit:number) : number;
}
}
声明文件不包含实现,它只是类型声明,把声明文件加入到 TypeScript 中:
CalcTest.ts 文件代码:
///
var obj = new Runoob.Calc();
// obj.doSum("Hello"); // 编译错误
console.log(obj.doSum(10));
下面这行导致编译错误,因为我们需要传入数字参数:
obj.doSum("Hello");
TypeScript
,来看下谷歌FLOW
作用: javascript类型检查
使用步骤
安装flow, npm init -y -> cnpm i flow-bin -D
package.json中增加执行指令, "flow": "flow"
初始化flow配置文件, npm run flow init
[ignore]: 忽略检测类型的文件
[include]: 需要检测类型的文件
在项目中使用如下:
A. 通过注释(不推荐)
// @flow 注释之后的内容才能被flow检测
/*: number */ 在需要检测的内容这样注释, 说明其中类型
// @flow
let a /*: number */ = 3;
a = 'cc'
console.log(a)
B. 直接改写js结构(需要babel, 类似ts语法了)
安装bebel, cnpm i babel-cli babel-preset-flow -D
创建.babelrc文件,
{
"presets": [
"flow"
]
}
package.json文件中添加 "build": "babel ./src -d ./dist"
npm run build 通过babel把新增加的: number去除掉, 方便转码上线(与下面的指令区分开来)
let a: number = 3;
a = 'abc';
console.log(a);
npm run flow 还是会检测数据类型
执行npm run flow, 检测js内容
number类型:
可以赋值的类型——数值, NaN, Infinity
let a: number = NaN
string类型
Boolean类型
void类型: 就是js中的undefined
null
Array类型(需要指定array的元素类型) :
let arr: Array = []
any类型
let test: any = 任意数据
// 声明一个函数类型, 函数参数声明类型, 返回值也要声明类型
const sum = (arr: Array<number>): number => {
let result = 0;
arr.forEach(item => {
result += item;
});
return result;
};
// 当声明一个函数变量时, 说明这个变量是函数,
//参数两个为数字, 返回值为数字
let temp = (a: number, b:number) => number;
// 最常见的ajax, 参数是函数时, 同时箭头后面代表返回值类型,
// 不写默认是undefined
const ajax = (callback: (data: Object) => void) {
}
//Maybe类型
// 问号代表可以是null或者undefined, 函数没有声明返回值,
// 即返回值也可以是undefined
const test = (a: ?number) {
console.log(a)
}
//类型的或操作
// 就是或操作, 两者类型选择一个
let a = number|string = 10;
a = 'abc'
//对象类型
const ajax = (option: { url:string, type: string,
success:(data: Object) => void }) {
}
ajax()// 报错, 因为函数参数是对象