typescript学习

1.TypeScript 基础类型

  TypeScriptJavaScript中几乎有相同的数据类型,不一样的是TypeScript更严格,在定义一个变量时须要声明数据类型。若是不声明,都认定为 Any 类型。编程

   a.布尔值           

  最基本的数据类型就是简单的true/false数组

 let isDone: boolean = false;

  b. 数字

  TypeScript里的全部数字都是浮点数。 这些浮点数的类型是 number函数

 let decLiteral: number = 6;
 let hexLiteral: number = 0xf00d;
 let binaryLiteral: number = 0b1010;
 let octalLiteral: number = 0o744;

  c.字符串

  字符串用法较多,经常使用有两种。ui

 1.定义变量   
 let name:string  = "momo";

 2.字符串模版
 let name1:string = "wang";
 let age:number = 24;
 let sences:string = `hello ,my name is ${name}.i am ${age} years old`

  d.数组

  TypeScript像JavaScript同样能够操做数组元素。 有两种方式能够定义数组。 第一种,能够在元素类型后面接上 [],表示由此类型元素组成的一个数组:this

  let list:number[] = [1,2,3]

  第二种方式是使用数组泛型,Array<元素类型>spa

 let list:Array<number> = [1,2,3];

   e.元组

  元组类型容许表示一个已知元素数量类型的数组,各元素的类型没必要相同。设计

 let x:[string,number];
 x = ['hello', 10];  // ok
 x = [10,'hello'];   // error

  f.枚举

  enum类型是对JavaScript标准数据类型的一个补充。使用枚举类型能够为一组数值赋予友好的名字。3d

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

  默认状况下,从0开始为元素编号。 你也能够手动的指定成员的数值.rest

 enum Color {Red = 1,Green ,Blue}
 let c:Color = Color.Green;
 console.log(c); // 2

  枚举类型提供的一个便利是你能够由枚举的值获得它的名字code

  例如,咱们知道数值为2,可是不肯定它映射到Color里的哪一个名字,咱们能够查找相应的名字:

 enum Color {Red = 1,Green ,Blue}
 let colorNumber:string = Color[2];
 console.log(colorNumber);  // Green

   g.Any

  有时候,咱们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。

  这些值可能来自于动态的内容,好比来自用户输入或第三方代码库。

  这种状况下,咱们不但愿类型检查器对这些值进行检查而是直接让它们经过编译阶段的检查。 那么咱们可使用 any类型来标记这些变量:

 let notSure:any = 4;
 notSure = 'momo';
 notSure = false;

    h.void

  某种程度上来讲,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你一般会见到其返回值类型是 void.

  声明一个void类型的变量没有什么大用,由于你只能为它赋予undefinednull

 let unusable:void = undefined;

 2.变量声明

  letconst是JavaScript里相对较新的变量声明方式。 

   let在不少方面与var是类似的,可是能够帮助你们避免在JavaScript里常见一些问题。 

   const是对let的一个加强,它能阻止对一个变量再次赋值。

   letconstES6中有详细解释说明,这里就很少阐述了。

3.数组

  数组解构

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

     这建立了2个命名变量 first 和 second。 至关于使用了索引,但更为方便

 first = input[0];
 second = input[1];

 

   你能够在数组里使用...语法建立剩余变量:

 let [first, ...rest] = [1, 2, 3, 4];
 console.log(first); // 1
 console.log(rest); //  [ 2, 3, 4 ]

  对象解构

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

     这经过 o.a and o.b 建立了 a 和 b 。 注意,若是你不须要 c 你能够忽略它。

     就像数组解构,你能够用没有声明的赋值:

 ({ a, b } = { a: "baz", b: 101 });

  要当心使用解构。 从前面的例子能够看出,就算是最简单的解构表达式也是难以理解的。

  尤为当存在深层嵌套解构的时候,就算这时没有堆叠在一块儿的重命名,默认值和类型注解,也是使人难以理解的。

  解构表达式要尽可能保持小而简单。 你本身也能够直接使用解构将会生成的赋值表达式。

4.接口

  TypeScript的核心原则之一是对值所具备的结构进行类型检查

  它有时被称作“鸭式辨型法”或“结构性子类型化”。

  在TypeScript里,接口的做用就是为这些类型命名和为你的代码或第三方代码定义契约

   接口初探

 function text(lableObj) {
    console.log(lableObj.lable);
 }
 var myObj = { size: 10, lable: "size 10" };
 text(myObj);  //size 10

  类型检查器会查看text的调用。 text有一个参数,并要求这个对象参数有一个名为lable类型为string的属性。

  须要注意的是,咱们传入的对象参数实际上会包含不少属性,可是编译器只会检查那些必需的属性是否存在,而且其类型是否匹配。

   然而,有些时候TypeScript却并不会这么宽松,咱们下面会稍作讲解。

  

  下面咱们重写上面的例子,此次使用接口来描述:必须包含一个lable属性且类型为string: 

interface lableValue{
    lable:string;
}
function text(lableObj:lableValue){
    console.log(lableObj.lable);
}
let myObj = {size:10,lable:"size 10"}
text(myObj);  //size 10

  lableValue接口就比如一个名字,用来描述上面例子里的要求。

  它表明了有一个 lable属性且类型为string的对象。

  须要注意的是,咱们在这里并不能像在其它语言里同样,说传给text的对象实现了这个接口。

  咱们只会去关注值的外形。 只要传入的对象知足上面提到的必要条件,那么它就是被容许的。

  还有一点值得提的是,类型检查器不会去检查属性的顺序,只要相应的属性存在而且类型也是对的就能够。

   可选属性

  接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。

  可选属性在应用“option bags”模式时很经常使用,即给函数传入的参数对象中只有部分属性赋值了。

interface SquareConfig{
    color?: string;
    width?: number;
}
function creatSquare(config:SquareConfig):{color:string,area:number}{
    let newSquare = {color:"white",area:0};
    if(config.color){
        newSquare.color = config.color;
    }
    if(config.width){
        newSquare.area = config.width;
    }
    return newSquare;
}
let mySquare = creatSquare({color:"black"})
console.log(mySquare); //{ color: 'black', area: 0 }

  带有可选属性的接口与普通的接口定义差很少,只是在可选属性名字定义的后面加一个?符号。

  可选属性的好处之一是能够对可能存在的属性进行预约义,好处之二是能够捕获引用了不存在的属性时的错误。

  值得一提的是,被圈上的部分是函数creatSquare的返回值,若是函数没有返回值,应该标记为:void

  

   只读属性

  一些对象属性只能在对象刚刚建立的时候修改其值。 你能够在属性名前用 readonly来指定只读属性:

interface Point{
    readonly x:number;
    readonly y:number;
}

  若是传入参数时,传入了接口中没有的参数,好比:

interface SquareConfig{
    color?: string;
    width?: number;
}
function creatSquare(config:SquareConfig):{color:string,area:number}{
    let newSquare = {color:"white",area:0};
    if(config.color){
        newSquare.color = config.color;
    }
    if(config.width){
        newSquare.area = config.width;
    }
    return newSquare;
}
let mySquare = creatSquare({colour:"black"})

  这个时候会获得一个错误,// error: 'colour' not expected in type 'SquareConfig'

    解决办法:

  最佳的方式是可以添加一个字符串索引签名,前提是你可以肯定这个对象可能具备某些作为特殊用途使用的额外属性。 若是 SquareConfig带有上面定义的类型的colorwidth属性,而且还会带有任意数量的其它属性,那么咱们能够这样定义它:

interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any;
}

  咱们稍后会讲到索引签名,但在这咱们要表示的是SquareConfig能够有任意数量的属性,而且只要它们不是colorwidth,那么就无所谓它们的类型是什么。

 

  函数类型

  除了描述带有属性的普通对象外,接口也能够描述函数类型。

  为了使用接口表示函数类型,咱们须要给接口定义一个调用签名。

  它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每一个参数都须要名字和类型。

interface SearchFunc{
    (source:string,subString:string):boolean;
}

  这样定义后,咱们能够像使用其它接口同样使用这个函数类型的接口。

  下例展现了如何建立一个函数类型的变量,并将一个同类型的函数赋值给这个变量。

interface SearchFunc{
    (source:string,subString:string):boolean;
}

let mySearch:SearchFunc;
mySearch = function(source:string,subString:string){
    let result = source.search(subString);
    return result > -1;
}

  对于函数类型的类型检查来讲,函数的参数名不须要与接口里定义的名字相匹配。 好比,咱们使用下面的代码重写上面的例子:

interface SeachFunc{
    (source:string,subString:string):boolean;
}
let mySeach:SeachFunc;
mySeach = function(src:string,sub:string):boolean{
    let result  = src.search(sub);
    return result > -1;
}

  函数的参数会逐个进行检查,要求对应位置上的参数类型是兼容的。

  若是你不想指定类型,TypeScript的类型系统会推断出参数类型,由于函数直接赋值给了 SearchFunc类型变量。

  函数的返回值类型是经过其返回值推断出来的(此例是 falsetrue)。

  若是让这个函数返回数字或字符串,类型检查器会警告咱们函数的返回值类型与 SearchFunc接口中的定义不匹配。

  

  可索引的类型

  与使用接口描述函数类型差很少,咱们也能够描述那些可以“经过索引获得”的类型,好比a[10]ageMap["daniel"]

  可索引类型具备一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。 

interface StringArray{
    [index:number]:string;
}

let myArray:StringArray;
myArray = ["bob","fred"];
let myStr = myArray[0];
console.log(myStr); //bob

  共有支持两种索引签名:字符串和数字

  能够同时使用两种类型的索引,可是数字索引的返回值必须是字符串索引返回值类型的子类型。

  这是由于当使用 number来索引时,JavaScript会将它转换成string而后再去索引对象。

  也就是说用 100(一个number)去索引等同于使用"100"(一个string)去索引,所以二者须要保持一致。

class Animal {
    name: string;
}
class Dog extends Animal {
    breed: string;
}

// 错误:使用数值型的字符串索引,有时会获得彻底不一样的Animal!
interface NotOkay {
    [x: number]: Animal;
    [x: string]: Dog;
}

  你能够将索引签名设置为只读,这样就防止了给索引赋值:

interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!

 

总结:

1.interface SeachFunc {};  至关于定义了类型,而且只能按照这个类型传值;

2.let mySeach:SeachFunc;  至关于具体了内容,进行怎么样的操做;

3.let myObj = mySeach("wang","w");  至关于实例化;

 

5.类

  下面看一个使用类的例子: 

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet():string {
        return "Hello, " + this.greeting;
    }
}

let greeter = new Greeter("world");
console.log(greeter.greet()); //Hello, world

  咱们声明一个 Greeter类。这个类有3个成员:一个叫作 greeting的属性,一个构造函数和一个 greet方法。

  你会注意到,咱们在引用任何一个类成员的时候都用了 this。 它表示咱们访问的是类的成员.

  最后一行,咱们使用 new构造了 Greeter类的一个实例。 它会调用以前定义的构造函数,建立一个Greeter类型的新对象,并执行构造函数初始化它。

  继承  

  在TypeScript里,咱们可使用经常使用的面向对象模式。

  基于类的程序设计中一种最基本的模式是容许使用继承来扩展示有的类。

class Animal{
    move(distanceInMeters:number = 0){
        console.log(`Animal moved ${distanceInMeters}`);
    }
}
class Dog extends Animal{
    bark(){
        console.log("woof!woof!");
    }
}
const dog = new Dog();
dog.bark();  //woof!woof!
dog.move(10);//Animal moved 10
dog.bark();//woof!woof!

  这个例子展现了最基本的继承:类从基类中继承了属性方法

  这里, Dog是一个 派生类,它派生自Animal 基类,经过 extends关键字。 派生类一般被称做 子类,基类一般被称做 超类

  由于 Dog继承了 Animal的功能,所以咱们能够建立一个 Dog的实例,它可以 bark()move()

 

class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}
class Snake extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 5) {
        console.log("Slithering...");
        super.move(distanceInMeters);
    }
}

class Horse extends Animal{
    constructor(name: string) { super(name); }
    move(distanceInMeters = 45){
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}

let sam = new Snake("Sammy the Python");
let tom:Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);

  这个例子展现了一些上面没有提到的特性。

  这一次,咱们使用 extends关键字建立了 Animal的两个子类: Horse和 Snake

  与前一个例子的不一样点是,子类包含了一个构造函数,它 必须调用 super(),它会执行基类的构造函数。

  并且,在构造函数里访问 this的属性以前,咱们 必定要调用 super()。 这个是TypeScript强制执行的一条重要规则。

  这个例子演示了如何在子类里能够重写父类的方法。 

  Snake类和 Horse类都建立了 move方法,它们重写了从 Animal继承来的 move方法,使得 move方法根据不一样的类而具备不一样的功能。

  注意,即便 tom被声明为 Animal类型,但由于它的值是 Horse,调用 tom.move(34)时,它会调用Horse里重写的方法

相关文章
相关标签/搜索