架构及设计目标
TS是JS的超集。
安装
npm i -g typescript
新建test.ts
var t : number = 1;
编译
tsc test.ts
编译结果test.js
var t = 1;
类型
可选的静态类型声明
var counter; // 未知(any)类型
var counter = 0; // number类型(推断出)
var counter : number; // number类型
var counter : number = 0; // number类型
变量、基本类型和运算符
基本类型
- boolean
var isDone: boolean = false;
- number
var height: number = 6;
- string
var name: string = 'blob';
- array
var list: number[] = [1,2,3];
var list:Array<number> = [1,2,3]; // 使用泛型数组类型Array
- enum 为了给一个数字集合更友好地命名。enum类型中的成员默认是从0开始,可以手动设置成员中的值更改这种默认行为
enum Color {Red, Green, Blue };
var c: Color = Color.Green;
- any 任意JavaScript值
var notSure: any = 4;
notSure = 'maybe a string'
notSure = false
var list:any[] = [1, true, 'free'];
list[1] = 100;
- void 在某种意义上,any的对立面就是void,即所有的类型都不存在的时候。即在一个函数没有返回值时看到他
function warnUser(): void {
alert('This is my warning message');
}
JS的原始类型中包括了undefined和null。在js中,undefined是全局作用域的一个属性,他会赋值给那些被声明但未被初始化的变量。null是一个字面量,可以被赋值给那些表示没有值的变量。
在TS中不能把null和undefined当做类型使用。
var、let和const
var mynum : number = 1;
let isValid : boolean = true;
const apiKey : string = 'OOOOObbbbb';
var声明的变量保存在最近的函数作用域中。
let声明的变量保存在最近的比函数作用域小的作用域块中
const关键字会创建一个保存在创建位置作用域中的常量。
联合类型
var path : string[]|string;
path = '/temp/log.xml';
path = ['/temp/log.xml', '/temp/errors.xml'];
path = 1; // error
联合类型用来声明可以存储多种类型值的变量。
类型守护
可以在运行时使用typeof或者instanceof对类型进行验证。TS语言服务会在if区寻找这些运算符,然后对应地修改类型
var x: any = {/*...*/}
if(typeof x === 'string') {
console.log(x.splice(3,1);// 错误,'string'上不存在splice方法
}
// x 依然是any类型
x.foo(); //合法
TS语言服务可以读懂在条件语句中使用typeof的用法。TS会自动推断出x一定是string类型,然后告诉我们splice方法不存在与string类型上。这种特性被称为类型守护
类型别名
type PrimitiveArray = Array<string|number|bollean>;
type MyNumber = number;
type NgScope = ng.Iscope;
type Callback = () => void;
环境声明
环境声明允许在TS代码中创建一个不会被编译到JS中的变量。这个特性是用来促进与现有Js代码、DOM,BOM结合而设计的。
interface ICustomConsole {
log(arg : string) : void;
}
declare var customConsole : ICustomConsole;
使用declare创建环境声明
customConsole.log('A log entry!');
算数运算符
流程控制语句
单一选择结构
var isValid : bollean = true;
if(isValid) {
alert('is valid!');
}
双选择结构
var isValid : boolean = true;
if(isValid) {
alert('Is valid');
} else {
alert('Is Not Valid');
}
三元操作符
var isValid : boolean = true;
var message = isValid ? 'Is valid!':'Is NOT valid';
alert(message);
多选结构
enum AlertLevel {
info,
warning,
error
}
function getAlertSubscribers(level: AlertLevel) {
var emails = new Array<string>();
switch(level) {
case AlertLevel.info:
emails.push('cst@domain.com');
break;
case AlertLevel.warning:
emails.push('development@domain.com');
emails.push('sysadmin@domain.com');
break;
case AlertLevel.error:
emails.push('development@domain.com');
emails.push('sysadmin@domain.com');
emails.push('mangement@domain.com');
break;
default:
throw new Error('Invalid argument!');
}
return emails;
}
getAlertSubscribers(AlertLevel.info);// ['cst@domain.com']
语句在顶部进行判断的循环
var i : number = 0;
while (i < 5) {
i += 1;
console.log(i);
}
语句在底部进行判断的循环
var i: number = 0;
do {
i += 1;
console.log(i);
} while(i < 5);
迭代对象的属性
var obj: any = { a:1, b:2, c:3 };
for (var key in obj) {
console.log(key+"="+obj[key]);
}
上面代码会将继承的属性也进行枚举,若只枚举自己的属性可以使用hasOwnProperty方法进行判断
计数器控制循环
for(var i: number = 0; i < 9; i++){
consonle.log(i);
}
函数
具名函数
function greet(name?:string): string {
if(name) {
return 'Hi!' + name;
} else {
return 'Hi!';
}
}
匿名函数
var greet = function(name?:string): string {
if(name) {
return 'Hi!' + name;
} else {
return 'Hi!';
}
};
箭头函数
var greet = (name:string): string => {
if(name) {
return 'Hi!' + name;
} else {
return 'Hi!';
}
};
回调函数
function sum(a: number, b: number, callback: (result: number) => void){
callback(a+b);
}
类
class Character {
funllname: string;
constructor(firstname: string, lastname: string) {
this.fullname = firstname + ' ' + lastname;
}
greet(name?: string) {
if (name) {
return `Hi!${name}!My name is ${this.fullname}`;
} else {
return `Hi!My name is ${this.fullname}`;
}
}
}
var spark = new Character('Jacob', 'Keyes');
var msg = spark.greet();
console.log(msg); // 'Hi!My name is Jacob Keyes'
nar msg1 = spark.greet('Dr. Halsey');
console.log(msg1);// 'Hi!Dr. Halsey!My name is Jacob Keyes'
接口
可以使用接口确保类拥有指定的结构
interface LoggerInterface {
log(arg: any): void;
}
class Logger implements LoggerInterface {
log(arg) {
if(typeof console.log === 'function') {
console.log(arg);
}else{
alert(arg);
}
}
}
也允许用接口来约束对象
interface UserInterface {
name: string;
password: string;
}
var user : UserInterface = {
name: '',
password: ' // password遗漏错误属性
};
命名空间
命名空间,又称为内部模块,被用于组织一些具有某些内在联系的特性和对象。命名空间能使代码结构更加清晰,
namespace Geometry {
interface VectorInterface {/**/} // 不export外部访问不到
export interface Vector2dInterface { /**/}
export interface Vector3dInterface {/**/}
export class Vector2d implements VectorInterface, Vector2dInterface {/**/}
export class Vector3d implements VectorInterface, Vector3dInterface {/**/}
}
var vector2dInstance:Geometry.Vector2dInterface = new Geometry.Vector2d();
var vector3dInstance:Geometry.Vector3dInterface = new Geometry.Vector3d();
应用
module Geometry {
export interface Vector2dInterface {
toArray(callback: (x: number[]) => void): void;
length():number;
normalize();
}
export class Vector2d implements Vector2dInterface {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
toArray(callback: (x: number[]) => void): void {
callback([this._x, this._y]);
}
length(): number {
return Math.sqrt(this._x * this._x + this._y * this._y);
}
normalize() {
var len = 1 ? this.length();
this._x *= len;
this._y *= len;
}
}
}
具体使用
var vector : Geometry.Vector2dInterface = new Geometry.Vector2d(2,3);
vector.normalize();
vector.toArray(function(vectorAsArray : number[]) {
console(`x:${vectorAsArray[0]} y:${vectorAsArray[1]}`);
});