http://www.patrickzhong.com/TypeScript/PREFACE.html

前言

  • TypeScript 官网大约从 2020 年开始要打造新版的官网,其中包括官网的样式,以及要重写大部分的文档。

快速上手

5分钟了解TypeScript

  • 在构造函数的参数上使用public等同于创建了同名的成员变量
class Student {
    fullName: string;
    constructor(public firstName: string, public middleInitial: string, public lastName: string) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}

Gulp

  • 即使我们使用了ES2015的模块语法,TypeScript还是会生成Node.js使用的CommonJS模块。 我们在这个教程里会一直使用CommonJS模块,但是你可以通过修改module选项来改变这个行为。
  • Babel是个十分灵活的编译器,将ES2015及以上版本的代码转换成ES5和ES3。 你可以添加大量自定义的TypeScript目前不支持的转换器。
  • 设置TypeScript目标为ES2015。 Babel稍后会从TypeScript生成的ES2015代码中生成ES5

React与webpack

  • 通常当你导入像"react"这样的路径,它会查看react包; 然而,并不是所有的包都包含了声明文件,所以TypeScript还会查看@types/react包
  • 可以使用npm link typescript来链接TypeScript到一个全局拷贝,但这不是常见用法
    • 注释:npm link将common模块创建成本地依赖包

从JavaScript迁移到TypeScript

  • 如果你在src目录外还有tests文件夹,那么在src里可以有一个tsconfig.json文件,在tests里还可以有一个。
  • 注释:任意数量参数的定义方法
myCoolFunction(function(x) { console.log(x) }, 1, 2, 3, 4);

function myCoolFunction(f: (x: number) => void, ...nums: number[]): void;
  • TypeScript提供了一些检查来保证安全以及帮助分析你的程序。 当你将代码转换为了TypeScript后,你可以启用这些检查来帮助你获得高度安全性。
    • 在某些情况下TypeScript没法确定某些值的类型。 那么TypeScript会使用any类型代替。
      • 可以使用noImplicitAny选项,让TypeScript标记出发生这种情况的地方,并给出一个错误。
    • 默认地,TypeScript把null和undefined当做属于任何类型。
      • null和undefined经常会导致BUG的产生,所以TypeScript包含了strictNullChecks选项来帮助我们减少对这种情况的担忧
      • 疑问:要当心,当你使用strictNullChecks,你的依赖也需要相应地启用strictNullChecks
    • 当你在类的外部使用this关键字时,它会默认获得any类型
      • TypeScript有noImplicitThis选项。 当设置了它,TypeScript会产生一个错误当没有明确指定类型(或通过类型推断)的this被使用时
      • 解决的方法是在接口或函数上使用指定了类型的this参数:
Point.prototype.distanceFromOrigin = function(this: Point, point: Point) {
    return this.getDistance({ x: 0, y: 0});
}

手册

基础类型

  • TypeScript里的所有数字都是浮点数或者大整数 。 这些浮点数的类型是number, 而大整数的类型则是 bigint。 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量。
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
let bigLiteral: bigint = 100n;
  • 元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
    • 当访问一个越界的元素会报错
  • 枚举类型提供的一个便利是你可以由枚举的值得到它的名字
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

console.log(colorName);  // 显示'Green'因为上面代码里它的值是2
  • 当我们在写应用的时候可能会需要描述一个我们还不知道其类型的变量。这些值可以来自动态内容,例如从用户获得,或者我们想在我们的 API 中接收所有可能类型的值。在这些情况下,我们想要让编译器以及未来的用户知道这个变量可以是任意类型。这个时候我们会对它使用 unknown 类型。
    • 如果你有一个 unknwon 类型的变量,你可以通过进行 typeof 、比较或者更高级的类型检查来将其的类型范围缩小
  • 在对现有代码进行改写的时候,any类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查
    • Object类型的变量只是允许你给它赋任意值 - 但是却不能够在它上面调用任意的方法,即便它真的有这些方法

接口

  • 一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用readonly来指定只读属性
interface Point {
  readonly x: number;
  readonly y: number;
}
  • TypeScript 具有ReadonlyArray<T>类型,它与Array<T>相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
  • 除了描述带有属性的普通对象外,接口也可以描述函数类型。
interface SearchFunc {
  (source: string, subString: string): boolean;
}
  • 可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型
    • 这是因为当使用number来索引时,JavaScript 会将它转换成string然后再去索引对象
  • 可以将索引签名设置为只读,这样就防止了给索引赋值
interface ReadonlyStringArray {
  readonly [index: number]: string;
}
  • 可以在接口中描述一个方法,在类里实现它
interface ClockInterface {
  currentTime: Date;
  setTime(d: Date): void;
}

class Clock implements ClockInterface {
  currentTime: Date = new Date();
  setTime(d: Date) {
    this.currentTime = d;
  }
  constructor(h: number, m: number) {}
}
  • 类是具有两个类型的:静态部分的类型和实例的类型
  • 当一个类实现了一个接口时,只对其实例部分进行类型检查
interface ClockConstructor {
  new (hour: number, minute: number);
}

class Clock implements ClockConstructor {
  currentTime: Date;
  constructor(h: number, m: number) {}
}
  • 一个接口可以继承多个接口,创建出多个接口的合成接口
interface Shape {
  color: string;
}

interface PenStroke {
  penWidth: number;
}

interface Square extends Shape, PenStroke {
  sideLength: number;
}
  • 一个对象可以同时作为函数和对象使用
interface Counter {
  (start: number): string;
  interval: number;
  reset(): void;
}
  • 当接口继承了一个类类型时,它会继承类的成员但不包括其实现
    • 接口同样会继承到类的 private 和 protected 成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现

函数

  • 书写完整函数类型
let myAdd: (x:number, y:number) => number =
    function(x: number, y: number): number { return x + y; };
  • 仅在等式的一侧带有类型,TypeScript编译器仍可正确识别类型
    • 这叫做“按上下文归类”,是类型推论的一种
let myAdd: (baseValue: number, increment: number) => number =
    function(x, y) { return x + y; };
  • 与普通可选参数不同的是,带默认值的参数不需要放在必须参数的后面。 如果带默认值的参数出现在必须参数前面,用户必须明确的传入undefined值来获得默认值。
function buildName(firstName = "Will", lastName: string) {
    return firstName + " " + lastName;
}
  • 在TypeScript里,你可以把所有参数收集到一个变量里
function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}
  • 提供一个显式的this参数。 this参数是个假的参数,它出现在参数列表的最前面
function f(this: void) {
    // make sure `this` is unusable in this standalone function
}
  • this: void意味着addClickListener期望onclick是一个函数且它不需要一个this类型。
interface UIElement {
    addClickListener(onclick: (this: void, e: Event) => void): void;
}
  • 查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。
  • function pickCard(x): any并不是重载列表的一部分,因此这里只有两个重载:一个是接收对象另一个接收数字
    • 疑问:实现函数需要定义返回类型吗?应该会根据重载自动做出检查吧?
function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
  // 实现
}

字面量类型

  • 目前 TypeScript 中有三种可用的字面量类型集合,分别是:字符串、数字和布尔值

联合类型和交叉类型

  • 使用联合的一种常用技术是使用字面量类型的单个字段,您可以使用该字段来缩小 TypeScript 可能的当前类型
type NetworkLoadingState = {
  state: "loading";
};

type NetworkFailedState = {
  state: "failed";
  code: number;
};

type NetworkSuccessState = {
  state: "success";
  response: {
    title: string;
    duration: number;
    summary: string;
  };
};

// 创建一个只代表上述类型之一的类型,但你还不确定它是哪个。
type NetworkState =
  | NetworkLoadingState
  | NetworkFailedState
  | NetworkSuccessState;
  • 联合的穷尽性检查:编译器能在我们没能覆盖可区分联合的所有变体时告诉我们

  • 类从基类中继承了属性和方法。 这里,Dog是一个_派生类_,它派生自Animal基类,通过extends关键字。 派生类通常被称作_子类_,基类通常被称作_超类_。
posted on 2022-07-21 19:32  噬蛇之牙  阅读(60)  评论(0编辑  收藏  举报