写客户端写腻了,所以决定学习web相关的知识,这两天简单了解了一下nestjs,没有TS基础初步学习还是觉得很吃力,于是打算看文档快速过一下TS的基础知识
数据类型 没什么好记录的,以下为需要注意的点,而不是体系记录
TS所有数字都是浮点数
string 类型可以使用“” 或者‘’ 包裹,模板字符串(用于多行文本或者内嵌表达式)使用``
使用联合类型解决了数组越界问题
保留any的任意值特性,但是应该注意尽量少用,代码不够优美。但是数组就很好用,let list: any[] = [1, true, free];
never类型是任何类型的子类型,也可以赋值给任意类型,然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。
symbol类型不可改变,且唯一,可用作键。
解构与展开 数组解构
1 2 3 4 let input = [1 , 2 , 3 , 4 ];let [first, ...rest] = input;console .log (first); console .log (rest);
对象解构
1 2 3 4 5 6 let o = { a : "foo" , b : 12 , c : "bar" }; let { a, b } = o;
数组展开
1 2 3 let first = [1 , 2 ];let second = [3 , 4 ];let bothPlus = [0 , ...first, ...second, 5 ];
需要注意这里的first和second都是浅拷贝,并且当展开对象时会丢失其方法。
接口 TS的接口很多变化,可以通过指定接口类型实现强或弱的限定,例如下例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function printLabel (labelledObj: { label: string } ) { console .log (labelledObj.label ); } let myObj = { size : 10 , label : "Size 10 Object" };printLabel (myObj);interface LabelledValue { label : string ; size : number , } function printLabel (labelledObj: LabelledValue ) { console .log (labelledObj.label ); } let myObj = {size : 10 , label : "Size 10 Object" };printLabel (myObj);
一个类实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Animal { name : string ; constructor (theName: string ) { this .name = theName; } move (distanceInMeters: number = 0 ) { console .log (`${this .name} moved ${distanceInMeters} m.` ); } } let passwd = "secrete_code" class Snake extends Animal { private age : number ; constructor (name: string ,age: number ) { super (name); this .age = age} move (distanceInMeters = 5 ) { console .log ("Slithering..." ); super .move (distanceInMeters); } get age () : number { return this .age ; } set age (NewAge: number ){ if (passwd && passwd =="123" ){ this .age = NewAge ; } else { console .log ("the password is wrong" ); } } } class Horse extends Animal { readonly age = 10 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 );
函数 最值得注意的就是函数是可以使用外部变量的,例子如下:
1 2 3 4 let z = 100 ;function add (x,y ){ return x+y+z; }
另外就是在TS和JS中都提供了两种定义函数的方法,类似于C++中定义普通函数和lamdda函数的方法。 1 2 3 4 5 6 7 function add (x, y ) { return x + y; } let myAdd = function (x, y ) { return x + y; };
函数中的this指针似乎并不是特别简单,尤其是在回调函数中的调用方式。另外就是在TS中有一种用法是调用一个函数会返回另外一个函数,而这个函数的this指针就会指向顶层windows或者undefined。
泛型 1 2 3 4 5 6 7 8 9 10 11 interface identityHaveLength{ length : number ; } function identity<T>(arg :T): T{ return arg; } function identityLength<T extends identityHaveLength (arg : T) > :T{ console .log (arg.length ); error return arg; }
类型兼容性 这实际上就是将static_cast从语言层面与引入了TS,但这真的是一件好事么,对于一个强类型的语言来说这是否会造成一定程度上的混乱呢。例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 interface Named { name : string ; } class Person { name : string ; } let p : Named ;p = new Person (); function greet (n: Named ) { alert ('Hello, ' + n.name ); } greet (p);
这个部分中的函数参数双向协变没有看懂具体作用
另外文档中有很多具体的兼容规则,需要在写代码的时候探讨。
高级类型部分 这个部分倒是很多有趣的东西,记录一些基本语法
交叉类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function extend<T, U>(first : T, second : U): T & U { let result = <T & U>{}; for (let id in first) { (<any>result)[id] = (<any>first)[id]; } for (let id in second) { if (!result.hasOwnProperty(id)) { (<any>result)[id] = (<any>second)[id]; } } return result; } class Person { constructor(public name: string) { } } interface Loggable { log(): void; } class ConsoleLogger implements Loggable { log() { // ... } } var jim = extend(new Person("Jim"), new ConsoleLogger()); var n = jim.name; jim.log();
联合类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface Bird { fly (); layEggs (); } interface Fish { swim (); layEggs (); } function getSmallPet ( ): Fish | Bird { } let pet = getSmallPet ();pet.layEggs (); pet.swim ();
即使用 | 来联合属性
另外还有一些通过is typeof instanceof关键字进行类型断言,的操作。
模块部分 模块在自身作用域中执行,而不是说全局作用域。如果需要使用,那么应该使用export 导出,import导入
装饰器 使用@expression形式,expression求值后必须为一个函数,在运行时被调用,
这个部分有很多要背下来的东西,慢慢记录把
你装饰的是… TypeScript 称之为 你的装饰器函数收到的参数 (签名) 类 (Class) ClassDecorator (target: Function)
target: 类的构造函数。
方法 (Method) MethodDecorator (target: any, propertyKey: string, descriptor: PropertyDescriptor)
target: 类的原型(如果是实例方法)或构造函数(如果是静态方法)。 propertyKey: 方法的名字 (字符串)。 descriptor: 方法的属性描述符 (内含 value,即函数本身)。
属性 (Property) PropertyDecorator (target: any, propertyKey: string)
target: 类的原型(如果是实例属性)或构造函数(如果是静态属性)。 propertyKey: 属性的名字 (字符串)。 (注意:没有 descriptor!)
参数 (Parameter) ParameterDecorator (target: any, propertyKey: string, parameterIndex: number)
target: 类的原型或构造函数。 propertyKey: 参数所在方法的名字。 parameterIndex: 参数在方法参数列表中的索引位置 (数字 0, 1, 2...)。