TypeScript入门

原创
2017/06/20 14:02
阅读数 37

ts编译器

安装编译器

npm install -g typescript

安装sublime插件

  • package control
  • install package
  • TypeScript

ts配置文件

  • 使用files属性
	{
	    "compilerOptions":{
	        "target":"es5",
	        "module":"amd",
	        "outFile":"./dist/main.js"
	    },
	    "files": [
			"core.ts",
        	"sys.ts",
	       "types.ts",
	       "scanner.ts",
       ]
   }
  • 使用 include 和 exclude属性
	{
	    "compilerOptions":{
	        "target":"es5",
	        "module":"amd",
	        "outFile":"./dist/main.js",
	        "sourceMap": true
	    },
	    "include":[
	        "src/**/*.ts"
	    ],
	    "exclude":[
	        "node_modules",
	        "**/*.spec.ts"
	    ]
	}

说明

  • compilerOptions可以被忽略,这时编译器会使用默认值
  • files 指定一个包含相对或绝对文件路径的列表。
  • include 和 exclude 属性指定一个文件glob匹配模式列表,支持的glob通配符有:
      • 匹配0或多个字符(不包括目录分隔符)
    • ?匹配一个任意字符(不包括目录分隔符)
    • **/递归匹配任意子目录

编译ts文件

tsc -w 

ts基础类型

boolean

let b:boolean = true

number

let n:number = 5

string

let s:string = "hello world"

元祖 [string,number]

let yz:[string,number]=['hello',56]
yz[0]

枚举 enum

enum Color {Red,Green,Blue='blue'};
let c:Color = Color.Blue;
console.log(c);

任意值 any

let notSure:any = 4;
notSure = 'string';
notSure = 123;

空值 void

function say():void{
	console.log('hello world')
}
say();
let u:void = undefined;
let n:void = null;

null 和 undefined

let u:undefined = undefined;
let n:null = null;

类型断言

let someValue:any = "this is a string"
let strLength:number = (<string>someValue).length;
let strLen:number = (someValue as string).length;

变量声明

let、const

块级作用域,const常量

解构数组

let input = [1,2];
let [first,last] = input;
console.log(first,last);

解构对象

let o = {
	a:"foo",
	b:12,
	c:"bar
}
let {a,b} = o;

解构对象-属性重命名

let {a:newName1,b:newName2} = o;

默认值

let o = {
	name:"zhangsan"
}
let {name,sex='男'} = o;

函数参数解构-默认值

type C = {name:string,age?:number}
function f({name,age=29}:C) :void {
	console.log(name,age);
}
f({name:"zhangsan"})

接口

接口

interface Person{
	name:string;
}
function f1(o:Person){
	console.log(o)
}
f1({name:'zhangsan',age:45})

接口-可选属性

interface Person{
	name:string;
	age?:number;
}
function createPerson(p:Person):Person{
	console.log(p)
	return p
}
createPerson({name:"zhangsan"})

接口-只读属性

interface Point{
	readonly x:number;
	readonly y:number;
}
let p1:Point = {x:10,y:20};
p1.x = 5; //error 只读属性赋值后不能更改

只读数组 ReadonlyArray<T>

let ro:ReadonlyArray<number> = [1,2,3,4,5];
ro[0] = 99; //error ReadonlyArray 类型的数组定义后无法修改
let arr: number[] = [1,2,3,4]
arr = ro; // error ReadonlyArray类型无法赋值给一个普通数组
arr = ro as number[]; // 但是可以用类型断言重写

索引签名

interface Person{
	name:string;
	age?:number;
	[propName:string]:any;
}
let p:Person = {name:"zhangsan",age:35,sex:"男"}

接口 - 函数

interface SearchFunc{
	(source:string,substring:string):boolean;
}
let mySearch:SearchFunc = (source:string,substring:string):boolean => {
	console.log(source,substring);
	return true;
}
console.log(mySearch("hahaha","heiheihei"))

接口 - 类实现

interface ReckonInterface {
	count:num;
	add(a:num,b:num);
}
class Reckon implements ReckonInterface{
	count:num;
	add(a:num,b:num){
		this.count = a+b;
	}
	constructor(h:number,m:number){}
}
let c = new Reckon(50,60);
c.add(33,44);

接口 - 扩展

interface Shape{
	color:string;
}
interface PenStroke{
	penWidth:number;
}
interface Square extends Shape,PenStroke{
	sideLength:number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
console.log(square)

修饰符 public protected private

class Animal{
	private name:string;
	protected name2:string;
	constructor(theName:string){this.name = theName;this.name2=theName;}
}

class Rhino extends Animal{
	constructor(){super("Rhino");}
	public getName(){
		return this.name2;
	}
}

let rhino = new Rhino();
let animal = new Animal("Goat");

console.log(rhino.getName()); 
console.log(rhino.name()); //error 属性名称是私有的
console.log(rhino.name2()); //error 属性名称是受保护的

修饰符 readonly

class Animal{
	readonly name:string;
	constructor(theName:string){this.name = theName;}
}
let animal = new Animal("haha");
console.log(animal.name);
animal.name = "zhangsan"; //name是只读的

参数属性

参数属性可以方便的在一个地方定义并初始化一个成员

class Animal{
	constructor(private name:string){}
	move(distanceInMeters:number){
		console.log(`${this.name} moved ${distanceInMeters}m.`);
	}
}
let animal = new Animal("dog");
animal.move(100);

存取器

ts支持getters/setters来截取对对象成员的访问

let passcode = "secret passcode2";
class Employee{
	private _fullName:string;
	get fullName():string{
		return this._fullName;
	}
	set fullName(newName:string){
		if(passcode && passcode=="secret passcode"){
			this._fullName = newName;
		}else{
			console.log("error:没有权限修改fullName")
		}
	}
}
let employee = new Employee();
employee.fullName = "Bob smith";
console.log(employee.fullName)

静态属性

静态属性存在于类本身

class Div{
	static origin = {x:10,y:100};
	constructor(x:number,y:number){
		this.x = x;
		this.y = y;
	}
}
let div = new Div(11,22);
console.log(div);
console.log(Div.origin.x,Div.origin.y);

抽象类

抽象类和接口类似,不同于接口,抽象类可以包含成员的实现细节

abstract class Animal{
	abstract say():void;
	move():void{
		console.log('roaming the earch...')
	}
}
class Dog extends Animal{
	say(){
		console.log("hello dog");
	}
}
let dog = new Dog();
dog.say();
dog.move();

把类当接口使用

因为类可以创建出类型,所以能够在可以使用接口的地方使用类。

class Point {
	x:number;
	y:number;
}
interface Ponit3d extends Point{
	z:number;
}
let point3d:Point3d = {x:1,y:2,z:3};
console.log(point3d)

函数

函数类型

可以给函数参数、返回值定义类型,只要参数类型匹配,参数名不用一致

function add(x:number,y:number):number{return x+y;}
let add2 = function(x:number,y:number):number{return x+y;}
let add3 = (x:number,y:number):number => x+y;
let add4:(xx:number,yy:number)=>number = (x:number,y:number):number => {return x+y;}
console.log(add(1,2));
console.log(add2(11,22));
console.log(add3(111,222));
console.log(add4(1111,2222));

推断类型

只需要在赋值语句的一边指定类型,ts编译器会自动识别出另一边的类型

let add1:(xx:number,yy:number)=>number = (x,y) => {return x+y};
let add2 = (x:number,y:number):number => {return x+y;}
console.log(add1(1,2));
console.log(add2(11,22));

可选参数和默认参数

ts函数参数名旁加?可以实现可选参数的功能,可选参数必须在必选参数后

默认参数不必在必选参数后,当不传参数时使用默认参数,若默认参数在必选参数前,必选明确传入undefined值来获得默认值。

function buildName(firstName:string="李",lastName?:string) {
	return firstName+ (lastName?" "+lastName:"");
}
console.log(buildName());
console.log(buildName(undefined,"四"));
console.log(buildName("张"));
console.log(buildName("张","三"));

剩余参数

在参数名前使用...可以收集函数剩余的所有参数到一个数组,剩余参数可以收集为0到多个参数,一个函数只能有一个剩余参数,剩余参数必须是最后一个参数。

function buildName(firstName:string,...restOfName:string[]) {
	return firstName+ " " + restOfName.join(" ");
}
console.log(buildName("张","三","男","21岁"));

重载

方法名称相同,但参数类型、顺序、个数不同、返回值不同是重载,编译时候编译器会帮助检查以避免错误调用

function pickCard(x:{name:string,age:number}[]):number;
function pickCard(x:number):{name:string,age:number};
function pickCard(x):any {
	if(typeof x=="object"){
		return Math.floor(Math.random() * x.length);
	}else if(typeof x=="number"){
		return cards[x%cards.length];
	}
}
let cards = [{name:"张三",age:24},{name:"李四",age:18},{name:"王五",age:67},{name:"赵六",age:41}]
console.log(pickCard(cards).name); //error 属性名name不存在于number上
console.log(Math.floor(pickCard(100))); //error pickCard(100)返回的是object,不是number

泛型

使用泛型类型可以使一个组件支持多种类型的数据,在

interface GenericIdentityFn<T>{
	(arg:T):T;
}
function identity<T>(arg:T):T{
	return arg;
}
let myIdentity:GenericIdentityFn<number> = identity;
console.log(myIdentity("88888")) //参数类型必须是number

泛型类

与接口一样,直接把泛型类放到类后面,可以帮助我们确认类的所有属性都在使用相同的类型。

class GenericNumber<T>{
	zeroValue:T;
	add:(x:T,y:T)=>T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = (x,y)=>{return x+y;};
console.log(myGenericNumber.add(5,6));

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = (x,y)=>{return x+y};
console.log(stringNumeric.add(stringNumeric.zeroValue,"test"));

泛型约束

可以使用 <T extends 类型>为泛型添加约束,来确保传入参数符合约束类型的值

function Identity<T>(arg:T):T{
	console.log(arg.length); //error: 类型T不能确定拥有.length属性
	return arg;
}

interface Lengthwise{
	length:number;
}
function loggingIdentity<T extends Lengthwise>(arg:T):T{
	console.log(arg.length);
	return arg;
}
loggingIdentity("hello world");
loggingIdentity(555); //error 555不是Lengthwise类型的参数

在泛型约束中使用类型参数

你可以声明一个类型参数,且它被另一个类型参数所约束,比如

class Findable<T> {
	constructor(public name:T){}
}

function find<T,U extends Findable<T>>(n:T,s:U) {
	console.log(n,s.name)
}
let s = new Findable("张三");
find("hello",s)

模块

ts的模块与es6模块一致

导出

任何声明(比如变量、函数、类、类型别名或接口) 都能够通过添加export关键字导出

export interface StringValidator{
    isAcceptable(s:string):boolean
}
export default xxx;

导入

import  * as validator from "./ZipValidator";
validator.say()

命名空间

在ts1.5里“内部模块”现在称作“命名空间”,命名空间可以为你的代码打个包,命名空间外无法访问命名空间内的代码,除非你使用export导出了这个变量或者类型,使用命名空间可以更方便的组织你的代码。

namespace Namespace{
    export class Test{
        private myName:string;
        constructor(name:string){
            this.myName = name;
        }
        say(){
            console.log('hello, '+this.myName);
        }
    }
}

let t = new Namespace.Test("张三");
t.say();

当应用变得越来越大时,我们可以将代码分离到不同文件中以便于维护。

当我们把一个命名空间分割在多个文件中的时候,可以使用引用标签来告诉编译器文件之间的关联,这样尽管被分割成了多个文件,仍然会被认为是同一个命名空间。

Namespace.js


namespace Namespace{
    export class Test{
        private myName:string;
        constructor(name:string){
            this.myName = name;
        }
        say(){
            console.log('hello, '+this.myName);
        }
    }
}

main.js

/// <reference path="Namespace.ts" />
namespace Namespace{
    export const pi = 3.14;
}

console.log(Namespace.pi);
let t = new Namespace.Test("张三");
t.say();

另一种简化命名空间操作的方法是使用 import q = x.y.x 给常用对象起个短名称。

namespace Shapes {
    export namespace Polygons{
        export class Triangle{}
        export class Square{}
    }
}

import polygons = Shapes.Polygons;
let sq = new polygons.Square();

相关文档

http://www.runoob.com/manual/gitbook/TypeScript/_book/index.html

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部