0%

TypeScript基本类型

TypeScript中的基本类型

布尔值 boolean

let isDone: boolean = false;

数字 number

和JavaScript一样,所有的数字都是浮点数 let score: number = 88;

字符串 string

可以用双引号(”)或单引号(’)表示字符串 let name: string = 'tony'

也可以使用模板字符串,可以定义多行文本和内嵌表达式,字符串被反引号(`)包围,并且以${expr}这种形式嵌入表达式。

1
2
let name = 'tony';
let message = `you name is ${$tony}`;

数组 array

有两种方式定义数组。

第一种方式是直接在元素类型后面跟上[],表示是由此类型组成的数组。

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

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

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

元组 tuple

元组允许表示一个已知元素和类型的数组,各元素的类型不必相同。

1
2
3
let x: [string, number];
x = ['tony', 19] //ok
x = [19, 'tony'] // error

当访问一个已知索引,会得到正确的类型,但是如果访问一个越界元素,那么会使用联合类型替代。

1
2
3
x[1] = 'dfdsfs' // error, x[1]是number类型,不可以赋值为string类型
x[3] = 'dfds' // ok,已经越界了,所以会使用联合类型,string|number,string没问题
x[3] = false // error,如上所示,已越界,boolean类型不属于string|number中的任一类型

枚举 enum

enum类型是对JavaScript标准数据类型的一个补充,使用枚举类型可以为一组数值赋予一个比较有友好的名字。

1
2
enum Status {OK= 1, Error = 2, Enable = 3};
let s: Status = Status.Ok; // s=1

默认情况下从0开始为元素赋值,也可以手动赋值。

1
2
enum Status {OK= 1, Error, Enable}; // ok=1, error=2, enable=3
enum Status {OK= 1, Error = 5, Enable = 4}; // 全部手动赋值

枚举类型提供的便利是我们可以用友好的名字来获得对应的值,反过来也可以由枚举的值来获得我们定义的名字。

1
console.log(Color[2]); // 'Error'

注意:如果定义的枚举类型用const来修饰了,那么无法用枚举的值来获得名字,会报错。

任意类型 any

有些变量我们并不知道他们具体是什么类型,可能会在程序中动态赋值,这种情况我们不希望类型检查器来对这些值检查而是让他们直接通过编译阶段的检查,那么我们用any类型来标记这些变量。

1
2
let user: any = 'tony';
user = {name: 'tony', age: 18};

当你知道一部分的数据的类型的时候,any类型也是非常有用的,比如我们常见的一个数组中有多个类型的数据。

1
let list: any[] = [1, true, 'fdsfds', {name:tony}];

没有类型 void

void和any来讲正好相反,void表示没有任何类型。当一个函数没有返回值的时候,通常可以设置为返回值类型是void。

1
function test():void { console.log('no return');}

对变量来来讲,void类型的变量没多大意义,只能赋值undefinednull

1
let unusable: void = undefined;

undefined 和 null

在TypeScript里面,undefined和null都有各自的类型undefinednull,他们是所有类型的子类型,和void一样,给变量什么为这两个类型没什么用。

永不存在的值的类型 never

never是那些永不存在的值的类型,哪些值是永不存在的?

  • 总是会抛出异常的函数表达式
  • 根本就不会有返回值的函数表达式
  • 箭头函数表达式的返回值类型
1
2
3
4
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}

never是任何类型的子类型,可以赋值给任何类型,但是never没有任何子类型,任何类型都不可以赋值给never(除过自己本身),any也不可以赋值给never。

类型断言

类型断言相当于类型转换,但不进行特殊的数据检查和解构,

类型断言有两种形式,一种是尖括号

1
2
3
let user: any = 'tony';
user = {name: 'tony', age: 18};
console.log((<string>user.age).length);

一种是as语法:

1
console.log((user.age as string).length);

变量声明

声明变量有let和const两种方式

let

let用法和var用法类似,但是,不同的是他们的作用域,var的作用域是函数作用域,但let是块级作用域。比如下面的例子,在函数test里面用var声明a变量,在if语句外面照样可以访问a变量。

1
2
3
4
5
6
function test(isOk: boolean) {
if (isOk) {
var a = 3;
}
console.log(a); // 3
}

但是如果使用let声明了变量,在包含它们的块之外,无法访问到。

1
2
3
4
5
6
function test(isOk: boolean) {
if (isOk) {
let a = 3;
}
console.log(a); // can not find 'a'
}

另一个特点是,拥有块级作用域的变量无法在声明它之前进行读写。

而且,用var声明时,后声明的会覆盖前面声明的,而let声明比较严格,在同一个块里面无法声明同一个变量两次。

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

1
2
3
4
for (let i = 0; i < 10; i++) {
setTimeout(function(){console.log(i);}, 100*i);
}
// 输出: 0, 1, 2, 3, 4,5, 6, 7, 8, 9, 10,

const

const和let一样具有同样的作用域,但是,他被赋值后,不能再改变,这里有两层意思:

  • 如果是基本类型,那么本身无法赋新的值
  • 如果是引用类型,本身引用的值无法改变,但是内部的值是可以改变的。
    1
    2
    3
    4
    const name = 'tony';
    console.log(name = '3'); // 报错,无法赋值
    const user = {name: 'tony', age: 18};
    console.log(user.name = 'tony1'); // ok

    解构

解构赋值语法是一个JavaScript语法表达式,这使得可以将值从数组或对象属性提取到不同的变量。

解构数组

用法:

1
2
3
4
5
let input = [1, 2, 3, 4];
let [first, second] = input;
// 在first和second已声明的情况下
[first, second] = input;
// first=1, second=2

这个用法相当于使用了索引,但更为方便。

可以使用...语法创建剩余变量:

1
2
let [first, ...second] = input;
// first=1, second=[2, 3, 4];

也可以忽略不关系的尾随元素:

1
2
let [first] = input;
// first=1

解构对象

语法从方括号([])变成了大括号({})。和解构数组不同的是,解构对象的变量必须是对象的属性,属性不一定,重要的是要包含在对象的属性里面。

1
2
3
4
let obj = {name: 'tony', age: 18, height: 175};
let {name, age1} = obj; // error
let {name, age} = obj; // ok, name=tony, age=18
let {name, height} = obj; // ok, name=tony, height=175

注意,通常JavaScript会把以{开始的语句解析为一个块,所以我们需要在解构已经声明过的变量时,需要加上括号()

1
2
3
let name: string, age: number;
{name, age} = obj; // 会报错
({name, age} = obj); // ok

也可以使用...语法创建剩余变量。

1
2
let {name, ...other} = obj; // name=tony, other={age: 18, height:175};
let {height, ...other} = obj; // height=175, other={name: 'tony', age: 18};

可以给属性重命名:

1
2
3
let {name: newName, age: newAge} = obj; // newName=tony, newAge=18
// 写法类似:
let newName = obj.name, newAge = obj.age;

可以在解构的时候设置默认值,以防止属性的值为undefined的时候解构的属性有值。适用于解构函数对象参数的情况。

1
2
let obj = {name: 'tony', age: 18, height: undefined};
let {name, height = 101, ...other} = obj; // height=101

函数声明

解构也可以使用在函数声明上。

1
2
3
4
5
6
7
type C = {a: string, b?: string};
function f({a, b}: C): void {
// ...
console.log('a:' + a + ' b:' + b );
}
f(); // error,需要传递形参
f({a: 'yes', b: 'no'}); // a:yes b:no

首先使用type定义了类型C,然后定义函数f,函数的参数是解构了类型C的两个形参ab。可以设定默认值:

1
2
3
4
function f({a, b} = {a: '', b: 0}): void {
// ....
}
f(); // ok , a:'' b: 0

展开

展开操作符正好和解构相反,允许将一个数组展开为另一个数组,或将一个对象展开为另一个对象。

1
2
3
4
let first = [1, 2, 3, 4];
let second = ['test', 'aaa'];
let both = [0, ...first, ...second];
// [0, 1, 2, 3, 4, "test", "aaa"]
码字辛苦,打赏个咖啡☕️可好?💘