【TS篇二】变量、数据类型、接口、解构赋值

一、变量声明

1.1 var

  • 作用域
  • 重复声明

1.2 let

  • 块级作用域
  • 在同一个块中不能重复声明

1.3 const

  • 声明同时必须赋值
  • 一定声明不可改变
    • 对象可以修改
  • 块级作用域

1.4 let vs const

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

二、基本数据类型

2.1 布尔值

let isDone: boolean = false;

2.2 数字

let amount: number = 6;

2.3 字符串

  • 类型

  • 模板字符串

    • 支持换行
    • 支持内嵌表达式
  • 和 JavaScript 一样,可以使用双引号,也可以使用单引号,推荐单引号

    let nickname: string = '张三';
    

还可以使用模板字符串(换行 + 嵌入表达式):

let nickname: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my nickname is ${
      
       nickname }.

I'll be ${
      
       age + 1 } years old next month.`;

2.4 数组

TypeScript像JavaScript一样可以操作数组元素。 有两种方式可以定义数组。 第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组:

let list: number[] = [1, 2, 3];

第二种方式是使用数组泛型,Array<元素类型>

let list: Array<number> = [1, 2, 3];

2.5 元组

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为stringnumber类型的元组。

// Declare a tuple type
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly
x = [10, 'hello']; // Error

2.6 Object

  • 允许赋任意值
  • 但是不能调用任意方法,即便它真的有
let foo: Object = {
    
    
  name: 'Jack',
  age: 18
}

知道即可,用的很少,没有类型校验和语法提示

2.7 Any

有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量:

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

2.8 Void

void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void

function warnUser(): void {
    
    
  alert("This is my warning message");
}

声明一个void类型的变量没有什么大用,因为你只能为它赋予undefinednull

let unusable: void = undefined;

2.9 Null 和 Undefined

void相似,它们的本身的类型用处不是很大:

// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;

默认情况下nullundefined是所有类型的子类型。 就是说你可以把 nullundefined赋值给number类型的变量。

然而,当你指定了--strictNullChecks 标记,nullundefined 只能赋值给 void 和它们各自。 这能避免 很多常见的问题。许在某处你想传入一个 stringnullundefined,你可以使用联合类型string | null | undefined

注意:我们推荐尽可能地使用--strictNullChecks ,因为它使你的代码更严谨,可以极大的减少出错的几率。

2.10 类型推断

有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。

通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。

类型断言有两种形式。 其一是“尖括号”语法:

let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;

另一个为as语法:

let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;

两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在TypeScript里使用JSX时,只有 as语法断言是被允许的。

2.11 其它

  • ReadonlyArray<T> 去除了数组的所有可变方法,确保数组创建后再也不能被修改

三、接口

TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

3.1 基本示例

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

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

类型检查器会查看printLabel的调用。 printLabel有一个参数,并要求这个对象参数有一个名为label类型为string的属性。 需要注意的是,我们传入的对象参数实际上会包含很多属性,但是编译器只会检查那些必需的属性是否存在,并且其类型是否匹配。 然而,有些时候TypeScript却并不会这么宽松,我们下面会稍做讲解。

下面我们重写上面的例子,这次使用接口来描述:必须包含一个label属性且类型为string

interface LabelledValue {
    
    
  label: string;
}

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

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

3.2 可选属性

接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。 可选属性在应用“option bags”模式时很常用,即给函数传入的参数对象中只有部分属性赋值了。

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

function createSquare(config: SquareConfig): {
    
    color: string; area: number} {
    
    
  let newSquare = {
    
    color: "white", area: 100};
  if (config.color) {
    
    
    newSquare.color = config.color;
  }
  if (config.width) {
    
    
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

let mySquare = createSquare({
    
    color: "black"});

3.3 只读属性

一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly来指定只读属性:

interface Point {
    
    
    readonly x: number;
    readonly y: number;
}

你可以通过赋值一个对象字面量来构造一个Point。 赋值后, xy再也不能被改变了。

let p1: Point = {
    
     x: 10, y: 20 };
p1.x = 5; // error!

readonly vs const

  • 常量使用 const
  • 对象属性使用 readonly

四、解构赋值

4.1 数组解构

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

上面的写法等价于:

first = input[0];
second = input[1];

利用解构赋值交换变量:

[first, second] = [second, first];

函数参数解构:

function f ([first, second]: [number, number]) [
  console.log(first)
  console.log(second)
]

f(1, 2)

解构剩余参数:

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

也可以忽略其它参数:

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

或者跳过解构:

let [, second, , fourth] = [1, 2, 3, 4]

4.2 对象解构

4.2.1 基本使用

示例一:

let o = {
    
    
    a: "foo",
    b: 12,
    c: "bar"
};
let {
    
     a, b } = o;

就像数组解构,你可以用没有声明的赋值:

let a: number,
  b: number;

({
    
    a, b} = {
    
    a: 123, b: 456})

console.log(a, b) // 123 456

你可以在对象里使用 ... 语法创建剩余变量:

let {
    
     a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;
4.2.2 属性解构重命名

你也可以给属性以不同的名字:

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

注意,这里的冒号不是指示类型的。 如果你想指定它的类型, 仍然需要在其后写上完整的模式。

let {
    
    a, b}: {
    
    a: string, b: number} = o;
4.2.3 默认值
function keepWholeObject(wholeObject: {
    
     a: string, b?: number }) {
    
    
    let {
    
     a, b = 1001 } = wholeObject;
}

4.3 展开操作符

  • 展开数组
  • 展开对象
    • 不会展开方法

4.4 解构赋值用于函数声明

type C = {
    
    a: string, b?: number}

function f ({
    
    a, b}: C): void {
    
    
  // ...
}

4.5 解构赋值用于加载指定模块成员

猜你喜欢

转载自blog.csdn.net/qq_39335404/article/details/134210128