TypeScript 中文教程基础部分上----翻译自TS官方

typescript 

 

为什么使用TS?

JS 中每一个值在不同的操作运行中表现出一系列不同的行为,比如说下面这个例子:

message.toLowerCase();
message();

逐行看下,第一行调用了message的toLowerCase方法,第二行直接调用message。

大部分情况下我们并不知道message的值,不能完全说出上面这段代码的执行结果。每一个操作完全依靠最开始的赋值。

思考这几个问题:

1 messag是否可以调用?

2 messag是否有一个可以调用的方法 toLowerCase?

3 如果有,toLowerCase是否可以调用?

4 即便上述message 和 message.toLowerCase都可以调用,那么他们返回什么呢?

确认上述四个问题,需要在编写代码时记住他们的返回值,赋值等情况,并且还要保证细节处理是对的,否则你很难把握最后的结果。

定义一个常量:

const message = "Hello World!";

这样定义后上面第一行代码返回小写的 hello world!

第二行还是会报错 

TypeError: message is not a function

如果我们能避免这样的错误就很好了。当我们运行代码时,JS 运行时便可以算出这个值的类型并知道他可以做什么。这部分要做(其实就是ts要做的)的就是像上面的报错一样告诉你 Hello World 不是一个方法。

对于一些基础类型的值比如 string 和 number类型,我们可以通过 typeof 判断他的类型。但是对于其他的类型比如 Object , 我们没有对应的运行时机制判断下面这个方法:

function fn(x) {
  return x.flip();
}

观察这段代码,他只会在参数带有一个可以调用的 flip方法时才会正常执行,但是 JS 不会立刻显示一条警告的信息,除非这个方法被执行。这个fn方法只有在调用了才知道发生了什么。

这样在你编写代码的时候你无法预测他的正确性。在这个例子中,type 的概念就是描述什么样的值可以当作参数传入,JS 是动态类型的,只有在运行后才能知道结果。

TS(当然了还有轻量级的 flowJS)正是一种备选方法,使用一种静态类型系统预测并检查你的代码。

 


 

 

静态类型检查

常用的基础类型有三种:string number (包含了int 和 float) boolean

数组的表达式:Array<number> 或者 number[ ]

any:可以是任何类型,并且不会触发 TS 的 checker

 

🔯 变量的类型声明

当你使用 const let var 声明一个变量时,你可以添加一个确定的类型

比如:let name: string = 'bowen';  注意:类型声明写在变量的右边

大部分情况下即使你不去声明一个类型,TS 也会在初始化的时候自行判断类型。

 

🔯 Function,TS 允许你指定输入(入参)类型和输出(返回值)类型

入参

例如:function greet(name: string) {
    console.log('hello' + name.toUpperCase() + '!');
  }

如果这样调用就会报错   🤢 greet(23) 

这样才对   😊 greet('bowen')

返回值,跟在参数列表之后声明

例如:function getFavoriteNumber(): number {
    return 24;
  }

Anonymous Functions 匿名函数

匿名函数和具名函数有些不同,当一个函数(匿名的)出现 TS 会计算出他将以什么样的形式被调用,以及自动判断入参类型。

例如:

const names = ['Alice', 'Bowen', 'Dimi']

names.forEach(function(name) {
  console.log(name.toUppercase()); 

      // 🤢 toUppercase 
      // 😊 toUpperCase
})

这里的匿名函数入参 name 会根据names 取值判断,所以判断name是string,进而判断是否具有toUpperCase方法

 

🔯 Object Types

除了上面提到的基础类型,你大部分时间会遇到的是Object类型。定义一个Object类型,可以简单看作就是在罗列出属性和他的类型

例如:

一个函数接受一个Object类型的入参

function printCoord(pt: { x: number; y: number }) {
  ......
}

我们在这里定义了一个Object参数,你可以使用 , 或者 ; 分割每一个属性

 

🔯 可选属性,Object类型可以指定部分或者全部的属性是可选的,只需要在可选参数的名称后面添加一个 ? 即可;

例如:

function printName(obj: { first: string; last?: string }) {
  ......
}

Both 😊
printName({ first: 'Bowen' })

printName({ first: 'Bowen', last: 'Nan' })

JS 中,如果你访问一个不存在的属性,你会得到一个 undefined ,所以在你定义了一个可选参数后,必须在使用前加以判断

例如:

function printName(obj: { first: string; last?: string }) {

  console.log(obj.last.toUpperCase()); // 🤢 这里 last可能是 undefined

        //😊正确的做法

       if (obj.last !== undefined) {
    console.log(obj.last.toUpperCase())
  }

  //或者

  console.log(obj.last?.toUpperCase());

}

 

🔯 联合类型

TS 的类型系统允许您使用各种各样的运算符在现有类型的基础上构建新类型。现在我们知道了如何编写一些类型,是时候开始以有趣的方式组合它们了。

定义一组联合类型

例如:

function printId(id: number | string) {
  console.log('your id is' + id)
}

Both 😊

printId(200)

printId('300')

怎么合理使用联合类型:对于联合声明的每一个类型成员都拥有可执行的方法

例如:

function printId(id: number | string) {

  console.log(id.toUpperCase())  //🤢因为number 不存在一个toUpperCase方法
}

解决方法和上面的可选类型类似:减少类型声明和逻辑代码的结合,看作是普通的JS逻辑判断

例如:

function printId(id: number | string) {
  if (typeof id === 'string') {
    console.log(id.toUpperCase())
  }else {
    console.log(id)
  }
}

当然了如果联合声明中的每个成员都有一样的属性方法,就可以忽略上述if else 的判断

例如:number[] (这是一个以number填充的Array) 和 string 都拥有一个 slice 的方法

function getFirstThree(x: number[] | string) {
  return x.slice(0, 3);

posted on 2022-01-04 18:32  Deflect-o-Bot  阅读(210)  评论(0编辑  收藏  举报