[译]<<Effective TypeScript>> 技巧41:理解any进化

306 阅读1分钟

本文的翻译于<<Effective TypeScript>>, 特别感谢!! ps: 本文会用简洁, 易懂的语言描述原书的所有要点. 如果能看懂这文章,将节省许多阅读时间. 如果看不懂,务必给我留言, 我回去修改.

技巧41:理解any进化

ts的变量类型一般在声明的时候已经定好了。声明之后,可以对类型进行细化,但是不能扩展。 但是有个例外:any的进化。

在js中你可能会写一个函数:用于根据范围产生一列数:

function range(start, limit) {
  const out = [];
  for (let i = start; i < limit; i++) {
    out.push(i);
  }
  return out;
}

将其转为ts:

function range(start: number, limit: number) {
  const out = [];
  for (let i = start; i < limit; i++) {
    out.push(i);
  }
  return out;  // Return type inferred as number[]
}

这里十分神奇的是,当out开始声明的时候,是any[]类型,到最后类型进化为:number[]。可以仔细查看每个out的类型:

function range(start: number, limit: number) {
  const out = [];  // Type is any[]
  for (let i = start; i < limit; i++) {
    out.push(i);  // Type of out is any[]
  }
  return out;  // Type is number[]
}

当我们把number 放入out中时,out类型会自动进化成 number[]

当有条件语句,any进化可以在不同分支发生,进化成不同类型:

let val;  // Type is any
if (Math.random() < 0.5) {
  val = /hello/;
  val  // Type is RegExp
} else {
  val = 12;
  val  // Type is number
}
val  // Type is number | RegExp

还有一种情况能引起 any进化。当val的初始值为null时,在try,catch可能会引起any进化:

let val = null;  // Type is any
try {
  somethingDangerous();
  val = 12;
  val  // Type is number
} catch (e) {
  console.warn('alas!');
}
val  // Type is number | null

有趣的是:any进化,只发生在隐式any,同时没有设置noImplicitAny:

let val: any;  // Type is any
if (Math.random() < 0.5) {
  val = /hello/;
  val  // Type is any
} else {
  val = 12;
  val  // Type is any
}
val  // Type is any

当我们在赋值之前使用隐式any,会报错:

function range(start: number, limit: number) {
  const out = [];
  //    ~~~ Variable 'out' implicitly has type 'any[]' in some
  //        locations where its type cannot be determined
  if (start === limit) {
    return out;
    //     ~~~ Variable 'out' implicitly has an 'any[]' type
  }
  for (let i = start; i < limit; i++) {
    out.push(i);
  }
  return out;
}

any进化只有对隐式any赋值的时候才会发生,当你对隐式any用读操作,就会得到错误。

隐式any函数调用后不会进化:

function makeSquares(start: number, limit: number) {
  const out = [];
     // ~~~ Variable 'out' implicitly has type 'any[]' in some locations
  range(start, limit).forEach(i => {
    out.push(i * i);
  });
  return out;
      // ~~~ Variable 'out' implicitly has an 'any[]' type
}

在ts中最常见的警告都是隐式any的,我们尽可能的要使用显示类型,让ts通过更精准类型检查