Typescript的一些基础知识(1)

190 阅读6分钟

前言:Typescript作为 JavaScript 的超集,在现在的项目中用的越来越多,那么我们就来学习一下关于Typescript的一些基础知识吧!

1.TypeScript 简介

TypeScript 其实是类型化的 JavaScript,它不仅支持 JavaScript 的所有特性,还在 JavaScript 的基础上添加了静态类型注解扩展。 比如:

let a: number = 1;

2.TypeScript的数据类型

TypeScript的数据类型主要分为基础数据类型和复杂数据类型。

2.1 基础数据类型

字符串

我们可以使用string类型表示任意的字符串(包括模板字符串),如下所示:

let firstname: string = 'Captain'; // 字符串字面量

let familyname: string = String('S'); // 显式类型转换

let fullname: string = `my name is ${firstname}.${familyname}`// 模板字符串

数字

我们可以使用number类型表示十进制整数、浮点数,以及二进制数、八进制数、十六进制数,如下所示:

/** 十进制整数 */

let integer: number = 6;

/** 十进制整数 */

let integer: number = Number(36);

/** 十进制浮点数 */

let decimal: number = 1.33;

/** 二进制整数 */

let binary: number = 0b0101;

/** 八进制整数 */

let octal: number = 0o725;

/** 十六进制整数 */

let hex: number = 0xf90b;

/** 大整数 */

let big: bigint =  100n;


注意:number和bigint是两个不同的类型,互不兼容

布尔值
/** 真 */

let TypeScriptIsGreat: boolean = true;

 /** 否 */

let TypeScriptIsBad: boolean = false;

Symbol
let s1: symbol = Symbol();

let s2: symbol = Symbol('42');

数组

首先,我们可以直接使用 [] 的形式定义数组类型,如下所示:

/** 子元素是数字类型的数组 */

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

/** 子元素是字符串类型的数组 */

let arrayOfString: string[] = ['x', 'y', 'z'];

同样,我们也可以使用 Array 泛型定义数组类型,如下所示:

/** 子元素是数字类型的数组 */

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

/** 子元素是字符串类型的数组 */

let arrayOfString: Array<string> = ['x', 'y', 'z'];

2.2 复杂数据类型

any

any 类型会在对象的调用链中进行传导,即所有 any 类型的任意属性的类型都是 any,如下代码所示:

let anything: any = {};

let z = anything.x.y.z; // z 类型是 any,不会提示错误

z(); // 不会提示错误

any 指的是一个任意类型,它是官方提供的一个选择性绕过静态类型检测的作弊方式。 我们可以把任何类型的值赋值给 any 类型的变量,也可以把 any 类型的值赋值给任意类型(除 never 以外)的变量,如下代码所示:

let anything: any = {};

anything.doAnything(); // 不会提示错误

anything = 1; // 不会提示错误

anything = 'x'; // 不会提示错误

let num: number = anything; // 不会提示错误

let str: string = anything; // 不会提示错误

但是请记住:Any is Hell(Any 是地狱)。

从长远来看,使用 any 绝对是一个坏习惯。如果一个 TypeScript 应用中充满了 any,此时静态类型检测基本起不到任何作用,也就是说与直接使用 JavaScript 没有任何区别。因此,除非有充足的理由,否则我们应该尽量避免使用 any。

unknown

unknown 是 TypeScript 3.0 中添加的一个类型,它主要用来描述类型并不确定的变量。在 3.0 以前的版本中,只有使用 any 才能满足这种动态类型场景。

比如在多个 if else 条件分支场景下,它可以用来接收不同条件下类型各异的返回值的临时变量:

let result: unknown;

if (x) {

  result = x();

} else if (y) {

  result = y();

} ...

与 any 不同的是,unknown 在类型上更安全。我们可以将任意类型的值赋值给 unknown,但 unknown 类型的值只能赋值给 unknown 或 any,如下所示:

let result: unknown;

let num: number = result; // 提示 ts(2322)

let anything: any = result; // 不会提示错误

使用 unknown 后,TypeScript 会对它做类型检测,而所有的类型缩小手段对 unknown 都有效,如:

let result: unknown;

if (typeof result === 'number') {

  result.toFixed(); // 此处 hover result 提示类型是 number,不会提示错误

}

void、undefined、null

void 类型,它仅适用于表示没有返回值的函数。即如果该函数没有返回值,那它的类型就是 void。 在 strict 模式下,声明一个 void 类型的变量几乎没有任何实际用处,因为我们不能把 void 类型的变量值再赋值给除了 any 和 unkown 之外的任何类型变量。

undefined 的最大价值主要体现在接口类型上,它表示一个可缺省、未定义的属性。 我们可以把 undefined 值或类型是 undefined 的变量赋值给 void 类型变量,反过来,类型是 void 但值是 undefined 的变量不能赋值给 undefined 类型。

const userInfo: {

  id?: number;

} = {};

let undeclared: undefined = undefined;

let unusable: void = undefined;

unusable = undeclared; // ok

undeclared = unusable; // ts(2322)

null 的价值主要体现在接口制定上,它表明对象或属性可能是空值。尤其是在前后端交互的接口,任何涉及查询的属性、对象都可能是 null 空对象,如:

const userInfo: {

  name: null | string

} = { name: null };

never

never 表示永远不会发生值的类型

首先,我们定义一个统一抛出错误的函数,示例如下(圆括号后 : + 类型注解 表示函数返回值的类型):

function ThrowError(msg: string): never {

  throw Error(msg);

}

以上函数因为永远不会有返回值,所以它的返回值类型就是 never。

同样,如果函数代码中是一个死循环,那么这个函数的返回值类型也是 never,如下所示:

function InfiniteLoop(): never {

  while (true) {}

}

never 是所有类型的子类型,它可以给所有类型赋值,但是反过来,除了 never 自身以外,其他类型(包括 any 在内的类型)都不能为 never 类型赋值。

在恒为 false 的类型守卫条件判断下,变量的类型将缩小为 never(never 是所有其他类型的子类型,所以是类型缩小为 never,而不是变成 never)。因此,条件判断中的相关操作始终会报无法更正的错误(我们可以把这理解为一种基于静态类型检测的 Dead Code 检测机制),如下代码所示:

const str: string = 'string';

if (typeof str === 'number') {

  str.toLowerCase(); // Property 'toLowerCase' does not exist on type 'never'.ts(2339)

}

基于 never 的特性,我们可以把 never 作为接口类型下的属性类型,用来禁止写接口下特定的属性,如:

const props: {

  id: number,

  name?: never

} = {

  id: 1

}

props.name = null; // ts(2322))

props.name = 'str'; // ts(2322)

props.name = 1; // ts(2322)

此时,无论我们给 props.name 赋什么类型的值,它都会提示类型错误,实际效果等同于 name 只读 。

object

object 类型表示非原始类型的类型,即非 number、string、boolean、bigint、symbol、null、undefined 的类型。如下所示的是用来表示 Object.create 的类型。

declare function create(o: object | null): any;

create({}); // ok

create(() => null); // ok

create(2); // ts(2345)

create('string'); // ts(2345)

参考

TypeScript入门实战笔记