let [first, ...rest] = [1, 2, 3, 4]; console.log(first); // outputs 1 console.log(rest); // outputs [ 2, 3, 4 ] let [first] = [1, 2, 3, 4]; console.log(first); // outputs 1 ---------------------------------------- 对象解构: let o = { a: "foo", b: 12, c: "bar" }; let { a, b } = o; let { a, ...passthrough } = o; let total = passthrough.b + passthrough.c.length; --------------------------------------- 属性重命名: let { a: newName1, b: newName2 } = o; 等价于: let newName1 = o.a; let newName2 = o.b; 这里的冒号不是指示类型的。 如果你想指定它的类型 let {a, b}: {a: string, b: number} = o; let { a, b = 1001 } = o; //默认值 ---------------------------------------- 函数申明解构: type C = { a: string, b?: number } function f( { a, b }: C ): void { } function f( { a, b = 1 } = { a: "", b: 0 } ): void { } f(); // ok, default to { a: "", b: 0 } ----------------------------------------------------------- interface 类型检查器不会去检查属性的顺序,编译器只会检查那些必需的属性是否存在,可以比接口规定的属性多。 interface X{ readonly a?:string; //一些对象属性只能在对象刚刚创建的时候修改其值 b?:number; } function ff(x:X):{a:string,b:number}{} //函数返回值规定类型 -------------------------------------------- 只读属性:一些对象属性只能在对象刚刚创建的时候修改其值 interface Point { readonly x: number; readonly y: number; } let p1: Point = { x: 10, y: 20 }; p1.x = 5; // error! ReadonlyArray<T>类型,把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改。 let a: number[] = [1, 2, 3, 4]; let ro: ReadonlyArray<number> = a; ro[0] = 12; // error! ro.push(5); // error! ro.length = 100; // error! a = ro; // error! 上面代码的最后一行,可以看到就算把整个ReadonlyArray赋值到一个普通数组也是不可以的。 但是你可以用类型断言重写:a = ro as number[]; 最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly。 ---------------------------------- 类静态部分与实例部分的区别: 类是具有两个类型的:静态部分的类型和实例的类型,类实现了一个接口时,只能够做到对其实例部分进行类型检查。 constructor存在于类的静态部分,所以不能检查。因此要检验类的构造函数不能用继承的方法,而是直接操作类的静态部分。 interface ClockConstructor { //用来检验构造函数 new (hour: number,s:string); } class DigitalClock{//校验构造函数不能用继承的方式, 也不再类的上面做操作, constructor(h: number) { } tick() { console.log("beep beep"); } } var dd = new DigitalClock(2);//new 之前做检验 function createClock(ctor: ClockConstructor) { //而是在传参数的时候做校验 return new ctor(1); } let digital = createClock(DigitalClock, 12, 17); ---------------------------------------------------------------- 接口继承类: 接口同样会继承到类的private和protected成员。接口里面的成员变量不能有访问修饰符、不能赋值、方法不能有访问修饰符和实现。 类里面没有方法的重载。有方法的重写。 子类必须调用super函数, super只能在构造函数中用, private只能在本类访问,不能在子类访问。protected可以在子类中访问。构造函数也可以被标记成protected,只能在子类实例化。 ---------------------------------------------------------------- 参数属性: class Animal { constructor(private name: string) { } } 构造函数里使用private name: string参数来创建和初始化name成员。 ---------------------------------------------------------------- 接口里面方法没有{}。抽象类里面方法要有{}。抽象类中的抽象方法必须在子类实现。类没有构造函数也可以有实例。静态属性和方法在类内部也是通过类.访问。 -------------------------------- class A{ static abc = "abc"; def = "def"; gret(){ console.log(A.abc); } } let a = new A(); console.log(a.gret());//abc let a1 : typeof A = A; a1.abc = "abc1"; let a3 = new a1(); a3.gret();//abc1 -------------------------------- js的参数是可传可不传的,ts的参数是一定要传的,函数的可选参数如果出现在最后面不传即可,如果出现在中间要传undefined才使用默认值。 -------------------------------- this: var suits = 4; let deck = { suits: 1, createCardPicker: function() { var suits = 3; return function() { var suits = 2; return {suit: this.suits}; //return 出去,不带着当前this,而是出去之后的this, } } } let cardPicker = deck.createCardPicker(); let pickedCard = cardPicker(); console.log( pickedCard.suit ); //4 -------------------------- var suits = 4; let deck = { suits: 1, createCardPicker: function() { var suits = 3; return () => { var suits = 2; return {suit: this}; } } } let cardPicker = deck.createCardPicker(); let pickedCard = cardPicker(); console.log( pickedCard.suit ); //1,箭头函数会绑定里面的this,出去之后也带着这个this,不会改变。箭头函数能保存函数创建时的 this值,而不是调用时的值 interface Card { suit: string; a:number; } interface Deck { suits: string; aa:number; createCardPicker(this: Deck): (a:number) => Card; //这个函数的返回值是一个函数 } interface D{ suits:number; } var suits = "suitssuits"; let deck : Deck = { //这个Deck校验deck, suits: "hearts", aa:333, createCardPicker: function(this: D) { //校验调用createCardPicker方法的对象, if(suits){ return (a:number) => { return {suit: this.suits,a:123}; //"hearts" } }else{ return function(a:number) { return {suit: this.suits,a:123}; //suitssuits } } } } let a = {s : deckDeck.createCardPicker,suits:333333334444444}; let s = a.s() console.log( s(1).suit ); let cardPicker = deck.createCardPicker(); let pickedCard = cardPicker(2); alert( pickedCard.suit ); -------------------------------- class Foo { x = 3; print() { console.log('x is ' + this.x); } } var f = new Foo(); f.print(); // Prints 'x is 3' as expected // Use the class method in an object literal var z = { x: 10, p: f.print }; z.p(); // Prints 'x is 10' var p = z.p; p(); // Prints 'x is undefined' -------------------------------- 泛型:function loggingIdentity<T extends Lengthwise>(arg: T): T {} 枚举: 通过字符串可以找到整数,通过整数也可以找到字符串。它包含双向映射(name -> value)和(value -> name) enum FileAccess { None, Read = 1, Write = 2, ReadWrite = 9, G = 123, } var FileAccess; (function (FileAccess) { FileAccess[FileAccess["None"] = 0] = "None"; FileAccess[FileAccess["Read"] = 1] = "Read"; FileAccess[FileAccess["Write"] = 2] = "Write"; FileAccess[FileAccess["ReadWrite"] = 9] = "ReadWrite"; FileAccess[FileAccess["G"] = 123] = "G"; })(FileAccess || (FileAccess = {})); ------------------------------------ 类型兼容性: interface i{ f:number; s(); } var f = { f:1, s:function () {}, ss:22, }; function ff(x:i){ // f的属性比i多,只要能够全部赋值就可以了,所可以比目标对象的属性多 x.s(); } ff(f); ---------------- 函数赋值: let x = (a: number) => 0; let y = (b: number, s: string) => 0; y = x; // OK,y函数要能够把x函数使用起来,y的参数要多于x x = y; // Error 解析js: var x = function (x) { return "x"; }; var y = function (x, y) { return '1'; }; x = y; y = x; ------ let items = [1, 2, 3]; items.forEach((item, index, array) => console.log(item)); items.forEach((item) => console.log(item)); ------ let x = () => ({name: 'Alice'}); let y = () => ({name: 'Alice', location: 'Seattle'}); x = y; // OK y = x; // Error