0
点赞
收藏
分享

微信扫一扫

第159期:对typescript的一些理解


关于TypeScript

关于TypeScript,我之前对它的理解现在想来还是太过于流于表面了。之前一直觉得它不过是提供了一种写法,然后我们按照它的写法,代码运行起来可以在编译时将代码中的错误抛出来,对于普通的项目,如果我们仅仅是从语法上从js 改为ts ,那么其实没什么必要。

这是我之前对TypeScript的一些粗浅的见解。

但是当我在项目中不断的使用TypeScript之后,我忽然发现我们不能仅仅将TypeScript作为一种语言,或者一种js的语法,它其实更接近一种规范,或者说它本身就是一种规范。

为什么这么说呢?如果我们不用TypeScript进行开发,那么我们的代码通常都是直接用js进行写,定义变量,或者函数接收参数的时候,我们都需要做各种类型的判断。但是如果我们换做TypeScript,那么定义变量的时候我们会直接定义好类型,函数接收什么样类型的参数,返回什么样类型的数据,都是需要事先考虑清楚的。否则,代码在编译时有可能就会报各种各样的错误出来。

TypeScript的手册中告诉我们如何去声明一个变量,如何声明一个接口:

interface LabelledValue {
    label: string; 
 }

function printLabel(labelledObj: LabelledValue) {
     console.log(labelledObj.label); 
  }

let myObj = {size: 10, label: "Size 10 Object"}; 

printLabel(myObj);

定义可选属性:

interface SquareConfig {
    color?: string;
    width?: number;
 }

索引类型:

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

枚举:

enum Direction {
  Up = 1,
  Down,
  Left,
  Right
}

如上,我们定义了一个数字枚举, Up使用初始化为 1。 其余的成员会从 1开始自动增长。 换句话说, Direction.Up的值为 1, Down为 2, Left为 3, Right为 4

泛型:

function identity<T>(arg: T): T {
  return arg;
}

除此之外,还有比如联合类型,交叉类型,可以为 null的类型等等如何定义的例子。

规范

手册中除了告诉我们如何去定义这些变量、类型之外,其实还有一节非常重要的内容讲的是TypeScript的使用规范。

比如:

  • 不要使用如下类型NumberStringBooleanObject。 这些类型指的是非原始的装盒对象,它们几乎没在JavaScript代码里正确地使用过。

/* 错误 */
function reverse(s: String): String;

应该使用类型numberstring,and boolean

  • 不要定义一个从来没使用过其类型参数的泛型类型。
  • 不要为返回值被忽略的回调函数设置一个any类型的返回值类型:

/* 错误 */
function fn(x: () => any) { x(); }

  • 应该给返回值被忽略的回调函数设置void类型的返回值类型:

/* OK */
function fn(x: () => void) { x(); }

因为使用void相对安全,因为它防止了你不小心使用x的返回值:

function fn(x: () => void) {
  var k = x(); // oops! meant to do something else 
  k.doSomething(); // error, but would be OK if the return type had been 'any' 
}

这也是在我们开发的项目中为什么禁止使用any声明变量的原因之一,因为使用any有可能会将很多错误遗漏掉,或者代码运行时无法检查出一些问题,所以我们声明变量及参数时,都是需要明确变量及参数的类型。

  • 不要在回调函数里使用可选参数除非你真的要这么做:

/* 错误 */
interface Fetcher {
  getObject(done: (data: any, elapsedTime?: number) => void): void;
}

这里有一种特殊的意义:done回调函数可能以1个参数或2个参数调用。 代码大概的意思是说这个回调函数不在乎是否有 elapsedTime参数, 但是不需要把这个参数当成可选参数来达到此目的 -- 因为总是允许提供一个接收较少参数的回调函数。

  • 不要因为回调函数参数个数不同而写不同的重载:

/* 错误 */
declare function beforeAll(action: () => void, timeout?: number): void;
declare function beforeAll(action: (done: DoneFn) => void, timeout?: number): void;

应该只使用最大参数个数写一个重载:

/* OK */
declare function beforeAll(action: (done: DoneFn) => void, timeout?: number): void;

因为回调函数总是可以忽略某个参数的,因此没必要为参数少的情况写重载。 参数少的回调函数首先允许错误类型的函数被传入,因为它们匹配第一个重载。

最后

原先我觉得TypeScript是一种语法而已,无非是声明变量、函数、类型的时候需要同时也声明一下对应的类型。但是写的越多,越觉得它其实就是一种规范,我们按照这种规范去写,代码的可读性慢慢的变得好起来了,编译时又能将错误抛出来,其实是一举两得。

当然,不同的团队有不同的规范,但是最根本的其实还是文档里讲的那些内容。


举报

相关推荐

0 条评论