一、基础类型/变量声明/接口/class

Created: May 10, 2021 9:34 AM

一、基础类型

数字,字符串,结构体,布尔值等

1.基本类型

    1. 布尔值
      1. let isDone: boolean = false;
  • 2.数字
    和JavaScript一样,TypeScript里的所有数字都是浮点数。 这些浮点数的类型是number.tsx let decLiteral: number = 6;

  • 3.字符串
    string表示文本数据类型typescript let sentence: string = `Hello, my name is ${ name }.

  • 4.数组tsx // 第一种,可以在元素类型后面接上[] let list: number[] = [1, 2, 3]; // 第二种方式是使用数组泛型,Array<元素类型>: let list: Array<number> = [1, 2, 3];

  • 5.元组 Tuple
    元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同tsx // Declare a tuple type let x: [string, number]; // 当访问一个越界的元素,会使用联合类型替代: x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型

  • 6.枚举
    enum类型是对JavaScript标准数据类型的一个补充.
    默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从1开始编号tsx enum Color {Red, Green, Blue} let c: Color = Color.Green;

  • 7.任意值
    我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。
    当你只知道一部分数据的类型时,any类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:tsx let list: any[] = [1, true, "free"];

  • 8.空值
    void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时.
    声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和nulltsx let unusable: void = undefined;

  • 9.Null 和 Undefined
    默认情况下null和undefined是所有类型的子类型。 就是说你可以把null和undefined赋值给number类型的变量。
    当你指定了—strictNullChecks标记,null和undefined只能赋值给void和它们各自。 这能避免很多常见的问题> 注意:我们鼓励尽可能地使用—strictNullChecks,但在本手册里我们假设这个标记是关闭的。

  • 10.Never
    never类型表示的是那些永不存在的值的类型。
  • 11.symbol

Symbols是不可改变且唯一的

  1. let sym2 = Symbol("key");

2.类型断言

有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息

  1. // 其一是“尖括号”语法:
  2. let someValue: any = "this is a string";
  3. let strLength: number = (<string>someValue).length;
  4. // 另一个为as语法
  5. let strLength: number = (someValue as string).length;

二、变量声明

let和const是JavaScript里相对较新的变量声明方式。 像我们之前提到过的, let在很多方面与var是相似的,但是可以帮助大家避免在JavaScript里常见一些问题。 const是对let的一个增强,它能阻止对一个变量再次赋值。

1. var 声明

标识符提升【变量提升】:它允许变量不声明就可以访问

捕获变量怪异之处:

  1. for (var i = 0; i < 10; i++) {
  2. setTimeout(function() { console.log(i); }, 100 * i);
  3. }
  4. // 10 10·······10
  5. 我们传给setTimeout的每一个函数表达式实际上都引用了相同作用域里的同一个i

作用域规则

var声明可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问(我们后面会详细介绍),包含它的代码块对此没有什么影响。 有些人称此为var作用域或函数作用域。 函数参数也使用函数作用域。

2. let 声明

块作用域:

  1. 当用let声明一个变量,它使用的是词法作用域或块作用域。 不同于使用 var声明的变量那样可以在包含它们的函数外访问,块作用域变量在包含它们的块或for循环之外是不能访问的。
  2. 拥有块级作用域的变量的另一个特点是,它们不能在被声明之前读或写

重定义及屏蔽

  1. 块级作用域变量不能用函数作用域变量来声明。 而是块级作用域变量需要在明显不同的块里声明。
  2. 在一个嵌套作用域里引入一个新名字的行为称做屏蔽

块级作用域变量的获取

当let声明出现在循环体里时拥有完全不同的行为。 不仅是在循环里引入了一个新的变量环境,而是针对 每次迭代都会创建这样一个新作用域。

  1. for (let i = 0; i < 10 ; i++) {
  2. setTimeout(function() {console.log(i); }, 100 * i);
  3. }
  4. // 0,1,2,3····9

3. const 声明

它们与let声明相似,但是就像它的名字所表达的,它们被赋值后不能再改变

4. let vs. const

使用最小特权原则,所有变量除了你计划去修改的都应该使用const。 基本原则就是如果一个变量不需要对它写入,那么其它使用这些代码的人也不能够写入它们,并且要思考为什么会需要对这些变量重新赋值。

5.解构

解构数组

  1. let input = [1, 2];
  2. let [first, second] = input; // 1, 2
  3. let [first, ...rest] = [1, 2, 3, 4];
  4. console.log(first); // outputs 1

对象解构

  1. let o = {
  2. a: "foo",
  3. b: 12,
  4. c: "bar"
  5. };
  6. let { a, b } = o;

属性重命名

  1. let { a: newName1, b: newName2 } = o;

默认值

  1. let { a, b = 1001 } = wholeObject;

展开

  1. let first = [1, 2];
  2. let second = [3, 4];
  3. let bothPlus = [0, ...first, ...second, 5];

三、接口

TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。

  1. interface SquareConfig {
  2. // 基础
  3. color: string;
  4. // 可选属性
  5. width?: number;
  6. // 只读属性.一些对象属性只能在对象刚刚创建的时候修改其值
  7. readonly x: number;
  8. //let p1: Point = { x: 10, y: 20 };
  9. // p1.x = 5; // error!
  10. // 额外的属性检查
  11. //最佳的方式是能够添加一个字符串索引签名,前提是你能够确定这个对象可能具有某些做为特殊用途使用的额外属性。
  12. [propName: string]: any;
  13. // 例子:
  14. // 只要它们不是color和width,那么就无所谓它们的类型是什么
  15. interface SquareConfig {
  16. color?: string;
  17. width?: number;
  18. [propName: string]: any;
  19. }
  20. }
  21. // 函数类型
  22. interface SearchFunc {
  23. (source: string, subString: string): boolean;
  24. }
  25. //可索引的类型
  26. interface StringArray {
  27. [index: number]: string;
  28. // 这个索引签名表示了当用number去索引StringArray时会得到string类型的返回值。
  29. // 共有支持两种索引签名:字符串和数字。
  30. // 但是数字索引的返回值必须是字符串索引返回值类型的子类型。 这是因为当使用number来索引时,JavaScript会将它转换成string然后再去索引对象。
  31. }
  32. let myArray: StringArray;
  33. myArray = ["Bob", "Fred"];
  34. // 类类型
  35. interface ClockInterface {
  36. currentTime: Date;
  37. setTime(d: Date);
  38. }
  39. // 继承接口
  40. interface Shape {
  41. color: string;
  42. }
  43. interface PenStroke {
  44. penWidth: number;
  45. }
  46. interface Square extends Shape, PenStroke {
  47. sideLength: number;
  48. }

readonly vs const
最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly。

混合类型

因为JavaScript其动态灵活的特点,有时你会希望一个对象可以同时具有上面提到的多种类型。

  1. interface Counter {
  2. (start: number): string;
  3. interval: number;
  4. reset(): void;
  5. }
  6. function getCounter(): Counter {
  7. let counter = <Counter>function (start: number) { };
  8. counter.interval = 123;
  9. counter.reset = function () { };
  10. return counter;
  11. }
  12. let c = getCounter();
  13. c(10);
  14. c.reset();
  15. c.interval = 5.0;

接口继承类

当接口继承了一个类类型时,它会继承类的成员但不包括其实现。

四、类

1. 类

  1. class Greeter {
  2. greeting: string; // 属性
  3. // 构造函数
  4. constructor(message: string) {
  5. this.greeting = message;
  6. }
  7. // 方法
  8. greet() {
  9. return "Hello, " + this.greeting;
  10. }
  11. }

2.继承

  1. class Animal {
  2. name: string;
  3. constructor(theName: string) { this.name = theName; }
  4. move(distanceInMeters: number = 0) {
  5. console.log(`${this.name} moved ${distanceInMeters}m.`);
  6. }
  7. }
  8. class Snake extends Animal {
  9. constructor(name: string) { super(name); }
  10. move(distanceInMeters = 5) {
  11. console.log("Slithering...");
  12. super.move(distanceInMeters);
  13. }
  14. }
  15. class Horse extends Animal {
  16. constructor(name: string) { super(name); }
  17. move(distanceInMeters = 45) {
  18. console.log("Galloping...");
  19. super.move(distanceInMeters);
  20. }
  21. }
  22. let sam = new Snake("Sammy the Python");
  23. let tom: Animal = new Horse("Tommy the Palomino");
  24. sam.move();
  25. tom.move(34);

3.公共,私有与受保护的修饰符

默认为public

理解private

  1. class Animal {
  2. private name: string;
  3. constructor(theName: string) { this.name = theName; }
  4. }
  5. new Animal("Cat").name; // 错误: 'name' 是私有的.

理解protected

protected成员在派生类中仍然可以访问

构造函数也可以被标记成protected。 这意味着这个类不能在包含它的类外被实例化,但是能被继承.

  1. class Person {
  2. protected name: string;
  3. protected constructor(theName: string) { this.name = theName; }
  4. }
  5. // Employee 能够继承 Person
  6. class Employee extends Person {
  7. private department: string;
  8. constructor(name: string, department: string) {
  9. super(name);
  10. this.department = department;
  11. }
  12. public getElevatorPitch() {
  13. return `Hello, my name is ${this.name} and I work in ${this.department}.`;
  14. }
  15. }
  16. // 是person的派生类constructor
  17. let howard = new Employee("Howard", "Sales");
  18. // constructor 被protected修饰,因此不能被实例化
  19. let john = new Person("John"); // 错误: 'Person' 的构造函数是被保护的.

4. readonly修饰符

你可以使用readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。

5.存取器

TypeScript支持通过getters/setters来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

  1. let passcode = "secret passcode";
  2. class Employee {
  3. private _fullName: string;
  4. get fullName(): string {
  5. return this._fullName;
  6. }
  7. set fullName(newName: string) {
  8. if (passcode && passcode == "secret passcode") {
  9. this._fullName = newName;
  10. }
  11. else {
  12. console.log("Error: Unauthorized update of employee!");
  13. }
  14. }
  15. }
  16. let employee = new Employee();
  17. employee.fullName = "Bob Smith";
  18. if (employee.fullName) {
  19. alert(employee.fullName);
  20. }

6.静态属性