TypeScript基础篇:常见类型详解 | 周末学习

本文已参与周末学习计划,点击查看详情

前言

TypeScript 作为 JavaScript 的超集,带来的最大优势就是静态类型,简单地说就是在编译过程中判断使用的变量类型是否符合预期。

一门语言在编译时报错,那么是静态语言,如果在运行时报错,那么是动态语言
后文中会将 TypeScript 简写为 ts,JavaScript 简写为 js

要想在项目中使用 Typescript,最基本的当然是把你的js的代码改造成ts。那么学习ts第一步~,先来了解写 Typescript 的数据类型。

类型检查方式

注意,ts 的类型检查本质是把 ts 转化为 js 时做了一次预编译,在编译过程中去检查数据类型是否符合预期。编译完成的 js 代码中不会加入额外的数据类型判断。

一、原始类型

有了 JavaScript 基础,以下基础类型的学习应该非常简单。

  • boolean 布尔值
  • number 数字类型
    • 包含二进制、十进制、十六进制等数
  • string 字符串类型
  • void
    • 包含 null 和 undfined
    • 默认是所有类型的子类型,因此可将void类型的值赋给其他类型
  • null
  • undefined
  • symbol (使用时 lib 必须添加 es6 的库文件)
  • bigint (使用时 lib 必须添加 es6 的库文件)

以上八种就是 ts 的基础类型,除了 void 类型大家应该都在js中使用过。void 类型包含 null 和 undefined 两种子类型,要特别注意的是 void、null 和 undefined 三种类型都属于 ts 的基本类型。

对于 symbol 和 bigint 两种数据类型,如果想在 ts 中使用,需要在 ts 配置文件中添加对应的辅助编译库。

// tsconfig.json
{
  "compilerOptions": {
    "lib": [
      "dom",
      "es5",
      "scripthost",
      "es2015.symbol"
    ]
  }
}

复制代码

基本类型定义语法

const decLiteral: number = 6

// 只有null和undefined可以赋值给void
const a: void = undefined
复制代码

二、其他类型

可以说以下类型才是ts类型学习的重点

1. any

any 类型意为任意类型,传入任意类型的数据都可以通过编译。any 类型数值来自动态内容或用户输入,使用 any 类型可以直接让他们通过编译检查的阶段(慎用)。

2. unknown

  • unknown 是ts3.0引入的新类型,是any类型对应的安全类型。
  • unknown 类型被确定是某个类型之前,它不能被进行任何操作比如实例化、getter、函数执行等等。
let value: unknown = [];

let concat = value.concat([1]);
console.log(concat);

// ERROR  Property 'concat' does not exist on type 'unknown'.
复制代码

通过以上 demo 可以看出,没有被确认具体类型的变量不能执行具体的实例化、函数执行等操作,即便赋值结果存在对应的方法。要想正确执行以上代码,需要加上类型保护,代码如下

let value: unknown = [];

if (value instanceof Array) {
    let concat = value.concat([1]);
    console.log(concat);
}

复制代码

3. never

表示永远不存在的类型,它可以是任何类型的子类型,也可以赋值给任何类型。

  • never 可以赋值给它自身
  • any 不能赋值给never

以下为常见的使用场景

// 抛出异常的函数永远不会有返回值
function error(message: string): never {
    throw new Error(message);
}

// 空数组,而且永远是空的
const empty: never[] = []
复制代码

4. 数组

数组有两种定义方式,可以使用泛型或直接在元素类型后加上[]

  • 使用泛型定义
const list: Array<number> = [1, 2, 3]
复制代码
  • 元素类型后面加上 []
const list: number[] = [1, 2, 3]
复制代码

在 ts 中声明一个数组时,只能定义数组元素术语哪一种类型或是any类型不再做类型限制,如果想要更加细粒度的控制数组中某一项的数据类型,可以使用元组类型。

5. 元组(Tuple)

  • 可以理解为一个已知元素数量和类型的数组。
  • 元组中包含的元素,必须与声明的类型一致,而且不能多、不能少,顺序必须一致
  • 元组属于数组的子类型
let x: [string, number];
x = ['hello', 10]; // OK
x = [10, 'hello']; // Error
复制代码

元祖越界

当给元祖类型插入一个未定义类型的新元素,直接打印元组可以看到新插入的元素,但是直接访问对应的新元素会报错。

const tuple: [string, number] = ['a', 1];
tuple.push(2); // ok
console.log(tuple); // ["a", 1, 2] -> 正常打印出来
console.log(tuple[2]); // Tuple type '[string, number]' of length '2' has no element at index '2'
复制代码

6. Object

与js中的object类似,表示非原始类型,也就是除 number、string、boolean、symbol、null 和 undefined 之外的类型。也就是说定义一个 object 类型的变量,可以将其赋值为普通对象、枚举、数组、元组等类型变量。

7. 枚举类型

枚举就是定义一组取值,变量的取值必须包含于这一组取值。

(1)数字枚举

  • 在定义一个枚举类型时如果没有赋值他的值会是默认的数组类型,从0开始依次累加。(当枚举中)
enum Direction {
    Up,
    Down,
    Left,
    Right
}

console.log(Direction.Up === 0); // true
console.log(Direction.Down === 1); // true
console.log(Direction.Left === 2); // true
console.log(Direction.Right === 3); // true
复制代码
  • 给第一个值(默认0)赋值后,后边的值会根据第一个值累加
enum Direction {
    Up = 10,
    Down,
    Left,
    Right
}

console.log(Direction.Up, Direction.Down, Direction.Left, Direction.Right); // 10 11 12 13
复制代码
  • 当给其中某一项赋值其他类型,在该值之后的枚举项默认值将会失效(取值时报错)
enum Direction {
    Up,
    Down,
    Left = 'nice',
    Right
}

let a: Direction = Direction.Down // 1
let b: Direction = Direction.Right // Enum member must have initializer.
复制代码

(2)字符串枚举

值类型为字符串的枚举。

enum Direction {
    Up = 'Up',
    Down = 'Down',
    Left = 'Left',
    Right = 'Right'
}

console.log(Direction['Right'], Direction.Up); // Right Up
复制代码

(3)异构枚举

enum Direction {
    Up = 'Up',
    Down = 23
}
复制代码
  • 其实就是混用数字枚举和字符串枚举。
  • 不能使用布尔值。
console.log(Direction[0]); // Up
复制代码

(4)常量枚举

使用 const 定义的枚举为常量枚举。枚举可以被 const 声明为常量,好处是编译后枚举对象就不存在了。

const enum Direction {
    Up = 'Up',
    Down = 'Down',
    Left = 'Left',
    Right = 'Right'
}

const a = Direction.Up;

// 编译后
var a = "Up";
复制代码

非要 TypeScript 保留对象 Direction ,那么可以添加编译选项 –preserveConstEnums

(5)反向映射

一个数字枚举可以通过枚举的 key 查找到对应的 value,反之也可以通过 value 查找到对应的 key,字符串枚举只能通过 key 找到 value,示例代码如下:

enum Enum {
    name = 'steven',
    age = 18
}

let a = Enum.age;
let nameOfA = Enum[a];

let b = Enum.name;
let nameOfB = Enum[b];

console.log(a); // 18
console.log(nameOfA); // age

console.log(b); // steven
console.log(nameOfB); // undefined
复制代码

看一下以上代码的编译结果(js)

var Enum;
(function (Enum) {
    Enum["name"] = "steven";
    Enum[Enum["age"] = 66] = "age";
})(Enum || (Enum = {}));
var a = Enum.age;
var nameOfA = Enum[a];
var b = Enum.name;
var nameOfB = Enum[b];
console.log(a);
console.log(nameOfA);
console.log(b);
console.log(nameOfB);
复制代码

将以上代码稍作改造,打印一下自执行函数中的 Enum 的值各位应该就能明白为何字符串枚举无法从 value 找到 key 了。

-   var Enum;
+   var Enum,o;
    (function (Enum) {
        Enum["name"] = "steven";
        Enum[Enum["age"] = 66] = "age";
+        o = Enum
    })(Enum || (Enum = {}));
    var a = Enum.age;
    var nameOfA = Enum[a];
    var b = Enum.name;
    var nameOfB = Enum[b];
    console.log(a);
    console.log(nameOfA);
    console.log(b);
    console.log(nameOfB);
    
    
+    console.log(o) // { '66': 'age', name: 'steven', age: 66 }

复制代码

END

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享