目录
一、基础类型
//*************************************
// Boolean
let isDone: boolean = false;
//*************************************
// 数字
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
//*************************************
// 字符串
let sname: string = 'bob';
// 模板字符串
let age: number = 37;
let sentence: string = `Hello,My name is ${sname},age is ${age}`
//*************************************
// 数组
let ilist: number[] = [1,2,3]
let ilist2: Array<number> = [1,2,3]
//*************************************
// 元祖
let x:[string,number];
x = ['hello', 2]
console.log(x[0].substr(1))
// console.log(x[1].substr(1))
//*************************************
// 枚举
enum Color {
Red = 1,
Green,
Blue
}
let c:Color = Color.Blue
// 可以获取colorName的名称
let colorName: string = Color[2]
//*************************************
// Any
let notSure:any = 4
notSure = 'maybe a string instead'
notSure = false
// 使用any可以调用方法,但是使用Object不能调用方法
let notSure2: any = 4
notSure2.toFixed()
// 使用Objcet不能调用方法
// let notSure3: Object = 4
// notSure3.toFixed()
//*************************************
// void
function warnUser() :void{
console.log('This is mt warning message!')
}
// void可以被赋值成undefined和null
let unusable: void = undefined
//*************************************
// NUll和Undefined
let u: undefined = undefined
let n: null = null
//*************************************
// Never(Never可以赋值给任何类型,但是任何类型不能赋值给never),多用于抛出异常
function error(message:string): never {
throw new Error(message)
}
//*************************************
// Objcet类型,是排除在基本类型之外的类型
declare function create(o: object | null): void;
create({prop:0})
create(null)
// create(42)
//*************************************
// 类型断言,类似于强制类型转换
let SomeValue: any = 'this is a string'
let stringLength: number = (<string>SomeValue).length
let stringLength2: number = (SomeValue as string).length
二、变量声明
//*************************************
// 结构数组
let inputNum: [number,number] = [1,2];
let [first,second] = inputNum;
function f([first,second]:[number,number]) {
console.log(first);
console.log(second);
}
f(inputNum);
let [first1,...recond1] = [1,2,3,4];
console.log(first1);
let [first2] = [1,2,3,4];
let [,second3,,forth3] = [1,2,3,4];
console.log(second3);
//*************************************
// 对象结构
let o = {
a: 'foo',
b: 12,
c: 'bar'
};
// let {a,b} = o;
// 获取剩余变量
let {a,...passthrought2} = o;
let total = passthrought2.b + passthrought2.c.length;
// 属性重命名,防止变量重复定义
let {a:newName1,b:newName2} = o;
//*************************************
// 展开,只能够展开数组,不能用于展开对象和类,因为这样会涉及到对象的重写
{
let first = [1,2]
let second = [3,4]
let bothPlus = [0,...first,...second]
}
三、接口
//*************************************
// 接口初探(可以检测接口中是否有label)
function printLabel(labelledObj:{label:string}) {
console.log(labelledObj.label)
}
let myObj = {size:10,label:'Size 10 Objcet'}
printLabel(myObj)
interface LabelledValue {
label: string;
}
function printLable2(labelledObj:LabelledValue) {
console.log(labelledObj.label)
}
printLable2(myObj)
//*************************************
// 可选属性(有些属性可能未定义)
interface SquareConfig {
color?: string
width?: number
}
function createSquare(config: SquareConfig): {color: string; area:number} {
let newSquare = {color: "white", area: 100};
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
//*************************************
// 只读属性
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = {x:10,y:20}
// p1.x = 5
//*************************************
// 接口的使用
interface MyPoint {
x: number;
y: number;
}
class Point2 implements MyPoint{
x: number;
y: number;
name: string;
}
function LogMyPoint(point: MyPoint) {
console.log(point.x,point.y)
}
var pointer2 = new Point2()
pointer2.x = 2
pointer2.y = 3
pointer2.name = 'zhangsan'
//*************************************
// 使用继承创建的接口是可以的,但是使用接口直接对象是不可以传入多于接口的类型的
LogMyPoint(pointer2)
// LogMyPoint({
// x: 10,
// y: 10,
// iy: 10
// })
// 简单的方法是通过类型转换
LogMyPoint({
x: 10,
y: 10,
name: 'zhangsan'
} as Point)
// 还可以通过签名
interface SquareConfig2 {
color?: string;
width?: number;
[propName:string]: any
}
//函数类型
// 可索引接口
//*************************************
// 类类型
interface Animal {
name: string;
eat():void;
}
class Cat implements Animal{
name: string;
eat(): void {
console.log('Cat',name,'is eat')
}
}
class Dog implements Animal{
name: string;
eat(): void {
console.log('Dog',name,'is eat')
}
}
//*************************************
//实现了简单工厂模式(没有多态的概念,但是却可以通过传递类的本身来模拟多态)
//接口不会对构造函数进行分析,因此任何的类都可以是认为直接转换为这个接口,从而实现不同类的多态
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick();
}
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new ctor(hour, minute);
}
class DigitalClock implements ClockInterface {
constructor(public h: number,public m: number) { }
tick() {
console.log("beep beep",this.h,this.m);
}
}
class AnalogClock implements ClockInterface {
constructor(public h: number,public m: number) { }
tick() {
console.log("tick tock",this.h,this.m);
}
}
let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);
digital.tick()
analog.tick()
//*************************************
// 继承接口(一个空的对象可以直接被转换成对应类型)
interface Shape {
color: string
}
interface Square extends Shape{
sideLength: number
}
let square = <Square>{}
square.color = 'blue'
square.sideLength = 10
//*************************************
// 接口可以多继承
interface PenStroke {
penWidth: number
}
interface Square extends Shape,PenStroke{
slideLength: number
}
四、类
//*************************************
// 可以使用public、protected、private,同C++一样
class Animal{
protected name: string;
public constructor(theName:string){
this.name = theName
}
}
class Rhino extends Animal{
public constructor() {
super('Rhino');
}
printName():void{
console.log(this.name)
}
}
//*************************************
// 声明只读类型,只读类型只能在构造函数中被赋值
class Octopus{
private readonly name:string
private readonly numberOfLegs: number = 8
public constructor(theName:string){
this.name = theName
}
}
// get、set
//*************************************
// 静态变量
class People{
static peopleSize = 0
public constructor(){
People.peopleSize += 1
}
static getPeopleSize(): number{
return People.peopleSize
}
}
new People()
new People()
console.log(People.getPeopleSize())
//*************************************
// set\get
class Employee{
private m_fullname:string;
get fullName():string{
return this.m_fullname;
}
set fullName(newName:string){
this.m_fullname = newName;
}
}
let employ = new Employee();
employ.fullName = "zhangsan";
console.log(employ.fullName)
//*************************************
// 抽象类
abstract class abstractAnimal {
abstract makeSound(): void;
move(): void{
console.log('Animal')
}
}
五、函数
// TypeScript可以根据return语句自动推断返回值类型,因此经常省略它
function add(x:number,y:number){
return x+y;
}
// 可选参数和默认参数
function buildName(firstName:string,lastName?:string) {
if(lastName)
return firstName + " " + lastName;
else
return firstName;
}
function buildName2(firstName:string,lastName = "Smith") {
return firstName + " " + lastName;
}
// 可选参数可以不出现在程序的最后,但是如果默认参数出现在前面,必须要指定到所有非可选参数
// 当传入的值为undefine时,默认传入的就是默认参数
function buildName3(firstName = "Will",lastName:string){
return firstName + " " + lastName;
}
let result = buildName3(undefined,"Adams");
// 剩余参数
function buildName4(firstName:string,...restofName:string[]){
return firstName + " " + restofName.join(" ");
}
// this
// let deck = {
// suits: ["hearts","spades","slubs","diamonds"],
// cards: Array(52),
// createCardPicker(){
// return ()=>{
// let pickedCard = Math.floor(Math.random() * 52);
// let pickedSuit = Math.floor(pickedCard / 13);
// return {suit: this.suits[pickedSuit], card: pickedCard % 13};
// }
// }
// };
// let cardPicker = deck.createCardPicker();
// let pickedCard = cardPicker();
//
// alert("card: " + pickedCard.card + " of " + pickedCard.suit);
// 改进
// 以面向对象的思路去改进,所有的Object都是对象,都需要定义一个类去规范接口的具体规范。
interface Card {
suit: string;
card: number;
}
interface Deck {
suits: string[];
cards: number[];
createCardPicker(this: Deck):()=>Card;
}
let deck: Deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
// 类似于Python,所有的函数都需要传递this指针作为自己的内部成员
createCardPicker: function(this: Deck) {
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
};
// 重载
// 重载是JS的特性,重载并不是定义不同的函数,而是通过同一个函数,去判断类型,从而有不同的执行逻辑
// 注意function pickMyCard(x):any并不是函数的重载
let suits = ["hearts","spades","clubs"];
function pickMyCard(x:{suit:string;card:number}[]):number;
function pickMyCard(x:number):{suit:string;card:number;};
function pickMyCard(x):any {
if(typeof x == "object"){
let pickedCard = Math.floor(Math.random()*x.length);
return pickedCard;
}
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
六、泛型
// 使用泛型
// 使用泛型,可以不丢失类的信息
import enumerate = Reflect.enumerate;
function identity<T>(arg: T):T{
return arg;
}
let output = identity<string>("Hello World");
// 也可以不使用类型,而是使用类型推断
let output2 = identity("myString");
function loggingIdentity<T>(arg: T[]):T[] {
console.log(arg.length);
return arg;
}
// 泛型类型
let myIdentitys:<U>(arg:U)=>U = identity;
// 泛型接口
interface GeneraicIdentityFn {
<T>(arg:T):T;
}
let ImyIdentitys:GeneraicIdentityFn = identity;
// 前面一个例子可以看出来,当接口中只有一个函数时,函数本身也可以被转换成接口
// 定义泛型接口时,可以将类型指定在类的本体上
interface GeneraicIdentityFn2<T> {
(arg:T):T;
}
// 泛型类
class GenericNumber<T>{
zeroValue:T;
add:(x:T,y:T)=>T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x,y) {
return x+y;
};
// 类的静态成员不能使用泛型
// 约束泛型
// 描述某种泛型一定需要包含某种接口
interface Lengthwise {
length: number;
}
function loggingIdentity2<T extends Lengthwise>(arg: T) {
console.log(arg.length);
return arg;
}
// 在泛型中使用类类型
// 在工厂函数中使用比较普遍
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
}
class Lion extends Animal {
keeper: ZooKeeper;
}
function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}
createInstance(Lion).keeper.nametag; // typechecks!
createInstance(Bee).keeper.hasMask; // typechecks!
七、枚举
enum Direction {
Up = 1,
Down,
Left,
Right
}
function SetDirection(dir:Direction) {
if(dir == Direction.Down){
console.log("Down")
}
}
// 字符串枚举
// 字符串枚举需要全部被初始化
enum DirectionStr {
Up = "Up",
Down = "Down",
Left = "Left",
Right = "Right"
}
enum E {
Foo,
Bar
}
function f(x:E) {
// TS能够判断不能够让x不等于任何类型
// if(x!=E.Foo||x!=E.Bar){
//
// }
}
// 枚举是运行时存在的对象
enum E2 {
X,Y,Z
}
function f1(obj:{X:number}) {
return obj.X;
}
f1(E2);
// 反向映射
enum Enum {
A
}
let a = Enum.A;
let nameOfA = Enum[a];//"A"
// 常量枚举,在编译阶段会被删除
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]
// 外部枚举
declare enum Enum3 {
A = 1,
B,
C = 2
}
八、类型推断
// 类型推论
let x = 3;
// 最佳通用类型
let x2 = [0, 1, null];
class Animal{
name:string
}
class Rhino extends Animal{
name: 'Rhino'
}
class Elephant extends Animal{
name: 'Elephant'
}
let zoo:Animal[] = [new Rhino(),new Elephant()];
// 上下文类型
window.onmousedown = function(mouseEvent: any) {
console.log(mouseEvent.button); //<- Now, no error is given
};
function createZoo(): Animal[] {
return [new Rhino(), new Elephant()];
}
九、类型兼容性
// 类型兼容性:
// 对于接口,只需要对象的类型实现了具体的结构,即使没有显示定义,也是兼容的
interface Named {
name: string;
}
class Person{
name:string;
}
let p:Named;
p = new Person();
// 比较两个函数
let x1 = (a:number)=>0;
let y1 = (b:number,s:string)=>0;
y1 = x1;
// x1 = y1;
// 使用比较少的参数可以赋值给比较多的参数,这在JS中是合法的
class TestEvent {
timestamp: number;
}
class TestMouseEvent extends TestEvent{
x: number;
y: number;
}
// 可以通过强制类型转换进行上转型和下转型
function TestEventListener(e: TestEvent) {
console.log((<TestMouseEvent>e).x);
}
TestEventListener(<TestEvent>{
timestamp: 123,
x: 10,
y: 10
});
// 枚举和数字类型兼容,枚举和枚举不兼容
enum Status{
Ready,
Waiting
}
enum Color {
Red,
Blue,
Green
}
let stat = Status.Ready;
// stat = Color.Green;
// 类:只要成员函数相同,类就是可以相互兼容的
class Animal{
feet: number;
constructor(name:string,numFeet:number){}
}
class Size{
feet: number;
constructor(numFeet:number){}
}
let a:Animal;
let b:Size;
a = b;
b = a;
// 泛型
//只影响内部的类型,因此,如果没有使用到泛型,可以直接赋值
interface Empty<T> {
data:T;
}
let x: Empty<number>;
let y: Empty<string>;
// x = y; // OK, because y matches structure of x
十、高级类型
// 高级类型
class Bird {
fly(){}
layEggs(){}
}
class Fish {
swim(){}
layEggs(){}
}
function getSmallPet(type: string):Fish|Bird {
if(type === "Fish"){
return new Fish();
}else{
return new Bird();
}
}
// 交叉类型能够访问成员变量中的所有变量
function getSmallPet2(): Fish & Bird{
return {
fly : function (){},
layEggs : function(){},
swim : function () {}
}
}
// 联合类型只能访问成员中的共有变量
let pet = getSmallPet("Fish");
pet.layEggs();
// pet.swim(); ERROR
// 判断联合类型是否具有某个成员
if((<Fish>pet).swim){
(<Fish>pet).swim();
}
// typeof类型保护
function padLeft(value: string,padding:string|number) {
if(typeof padding === "number"){
return Array(padding + 1).join(" ") + value;
}
if(typeof padding === "string"){
return padding + value;
}
throw new Error("Expected string or number")
}
let left = padLeft("Hello","Tom");
let right = padLeft("Hello",18);
// instanceof类型保护
interface Padder {
getPaddingString(): string
}
class SpaceRepeatingPadder implements Padder {
constructor(private numSpaces: number) { }
getPaddingString() {
return Array(this.numSpaces + 1).join(" ");
}
}
class StringPadder implements Padder {
constructor(private value: string) { }
getPaddingString() {
return this.value;
}
}
function getRandomPadder() {
return Math.random() < 0.5 ?
new SpaceRepeatingPadder(4) :
new StringPadder(" ");
}
// 类型为SpaceRepeatingPadder | StringPadder
let padder: Padder = getRandomPadder();
if (padder instanceof SpaceRepeatingPadder) {
padder; // 类型细化为'SpaceRepeatingPadder'
}
if (padder instanceof StringPadder) {
padder; // 类型细化为'StringPadder'
}
// 类型别名
type Name = string;
type NameResolver = ()=>string;
type NameOrResolver = Name | NameResolver;
// 字符串字面类型
// 字符串字面类型可以作为枚举使用
type Easing = "ease-in"|"ease-out"
function animate(easing:Easing) {
if(easing === "ease-in"){
}
else if(easing === "ease-out"){
}
}
// 也可以用来区分函数重载
function createElement(tagName:"img");
function createElement(tagName:"input");
function createElement(tagName:"div");
function createElement(tagName:string){
if(tagName === "img"){
}
}
createElement("img");
// 数字字面类型(很少使用)
function rollDie(): 1 | 2 | 3 | 4 | 5 | 6 {
return 1;
}
// 可辨识联合
// 其中kind作为可辨识联合的属性
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square|Rectangle;
// 可辨识联合可以为代码提供语法自动提示
function area(s:Shape) {
switch (s.kind) {
case "square":return s.size*s.size;
case "rectangle":return s.width*s.height;
}
}
// 多态的this类型
class BasicCalculator{
public constructor(protected value:number=0){
}
public currentValue():number{
return this.value;
}
public add(operand:number):this{
this.value += operand;
return this;
}
}
// 通过返回this,可以让这个类型得到持续的加工
let v = new BasicCalculator(2).add(3).add(4).currentValue();
// 当新的类继承后,可以使用同样的方法,并且新的对象中this永远是子类的this
class ScientificCalculator extends BasicCalculator{
public constructor(value=0){
super(value);
}
public sin():this{
this.value = Math.sin(this.value);
return this;
}
}
let v2 = new ScientificCalculator(2).add(2).sin().currentValue();
十一、Symbols
在部分编译器中会报错
十二、迭代器和生成器
let list = [4, 5, 6];
// 其中for...in...获取的是键的集合
for (let i in list) {
console.log(i); // "0", "1", "2",
}
// for...of...获取的是值的集合
for (let i of list) {
console.log(i); // "4", "5", "6"
}
十三、模块
// TypeScript中内部模块被称作命名空间
// 导出,任何的声明都可以使用export导出
export interface StringValidator {
isAcceptable(s:string):boolean;
}
export const numberRegexp = /^[0-9]+$/;
// 对导出的部分重命名
class ZipCodeValidator{
}
// export {ZipCodeValidator}
export {ZipCodeValidator as mainValidator};
// 重新导出
// export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
// export * from "module"
// 导入
// 导入一个模块中的某个导出内容
// import { ZipCodeValidator } from "./ZipCodeValidator";
// let myValidator = new ZipCodeValidator();
// 可以对导入内容重命名
// import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
// let myValidator = new ZCV();
// 将整个模块导入到一个变量,并通过它来访问模块的导出部分
// import * as validator from "./ZipCodeValidator";
// let myValidator = new validator.ZipCodeValidator();
// 具有副作用的导入模块
// 尽管不推荐这么做,一些模块会设置一些全局状态供其它模块使用。 这些模块可能没有任何的导出或用户根本就不关注它的导出。 使用下面的方法来导入这类模块:
// import "./my-module.js";
// 默认导出
// declare let $:JQuery;
// export default $;
// import $ from "JQuery";
// $("button.continue").html( "Next Step..." );
// 默认导出
// 默认导出后,导入的类为默认导出的重命名
// 可以认为,默认导出的类可以没有类名或者函数名
// export default class ZipCodeValidator {
// static numberRegexp = /^[0-9]+$/;
// isAcceptable(s: string) {
// return s.length === 5 && ZipCodeValidator.numberRegexp.test(s);
// }
// }
//
// import validator from "./ZipCodeValidator";
// let myValidator = new validator();
// 再例如
// export default "123";
//
// import num from "./OneTwoThree";
// console.log(num); // "123"
// export = 和 import = require()