写客户端写腻了,所以决定学习web相关的知识,这两天简单了解了一下nestjs,没有TS基础初步学习还是觉得很吃力,于是打算看文档快速过一下TS的基础知识

orange

数据类型

没什么好记录的,以下为需要注意的点,而不是体系记录

  • 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); // outputs 1
console.log(rest); // outputs 2,3,4
对象解构
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 }) {   //仅检查是否有名为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 //属性使用readonly,变量使用const
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
// Named function
function add(x, y) {
return x + y;
}

// Anonymous function
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 { /// 如果这里是class,是否会报错呢?
name: string;
}

class Person {
name: string;
}

let p: Named;
// OK, because of structural typing
p = new Person();

function greet(n: Named) {
alert('Hello, ' + n.name);
}
greet(p);// 这里仅检查目标属性,即named的属性。

这个部分中的函数参数双向协变没有看懂具体作用

另外文档中有很多具体的兼容规则,需要在写代码的时候探讨。

高级类型部分

这个部分倒是很多有趣的东西,记录一些基本语法

交叉类型
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(); // okay
pet.swim(); // errors
即使用 | 来联合属性

另外还有一些通过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...)。

  • 本站由 Edison.Chen 创建。
    本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

    undefined