我是靠谱客的博主 花痴橘子,这篇文章主要介绍TypeScript ---- 初识基础篇TypeScript ---- 初识基础篇,现在分享给大家,希望可以做个参考。

TypeScript ---- 初识基础篇

写在前面:本篇文章篇幅有点长,适合正打算学习TS的小白,如果有一定基础的大神可以忽略本篇文章。文章并非完全原创,大部分内容都是从网上其他文章搬运过来的,再在其中添加上自己的一些理解和总结,如果有涉及侵权请联系我,会及时做出整改。

一、基本类型

1.1 String类型

复制代码
1
2
3
let name: string = "张三"; // ES5: var name = "张三";

1.2 Number类型

复制代码
1
2
3
let num: number = 3; // ES5: var num = 3;

1.3 Boolean类型

复制代码
1
2
3
let bool: boolean = false; // ES5: var bool = false;

1.4 Symbol类型

复制代码
1
2
3
4
5
6
const symb = Symbol(); let obj = { [symb]: "张三" } console.log(obj[symb]); // 张三

1.5 Array类型

复制代码
1
2
3
4
5
let list: number[] = [1, 2, 3]; // ES5: var list = [1,2,3]; let list: Array<number> = [1, 2, 3]; // Array<number>属于泛型语法 // ES5: var list = [1,2,3];

1.6 Enum类型
枚举类型。使用枚举可以定义一些带名字的常量。使用枚举可以清晰的表达意图或创建一组有区别的用例。TypeScript支持数字和字符串枚举。

  • i. 数字枚举
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum Direction { UP, RIGHT, DOWN, LEFT } let dir: Direction = Direction.UP; // ES5: "use strict"; var Direction; (function(Direction) { Direction[(Direction["UP"] = 0)] = "UP"; Direction[(Direction["RIGHT"] = 1)] = "RIGHT"; Direction[(Direction["DOWN"] = 2)] = "DOWN"; Direction[(Direction["LEFT"] = 3)] = "LEFT"; })(Direction || (Direction = {})); var dir = Direction.UP;

默认情况下,UP的初始值为0,其余的成员会从1开始自动增长。换句话说,Direction.RIGHT的值为1,Direction.DOWN的值为2,Direction.LEFT的值为3。

  • 也可以给枚举值设置初始值,则枚举值会从1开始自增,即1,2,3,4。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum Direction { UP = 1, RIGHT, DOWN, LEFT } let dir: Direction = Direction.UP; // ES5: "use strict"; var Direction; (function(Direction) { Direction[(Direction["UP"] = 1)] = "UP"; Direction[(Direction["RIGHT"] = 2)] = "RIGHT"; Direction[(Direction["DOWN"] = 3)] = "DOWN"; Direction[(Direction["LEFT"] = 4)] = "LEFT"; })(Direction || (Direction = {})); var dir = Direction.UP;
  • 在中间的枚举值设置初始值,Enum不会关心也不会计算这个值的生成,而是会从0开始自增,遇见设置的初始值时,随后由这个初始值开始递增。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum Direction { UP, RIGHT, DOWN = 3, LEFT } let dir: Direction = Direction.UP; // ES5: "use strict"; var Direction; (function(Direction) { Direction[(Direction["UP"] = 0)] = "UP"; Direction[(Direction["RIGHT"] = 1)] = "RIGHT"; Direction[(Direction["DOWN"] = 3)] = "DOWN"; Direction[(Direction["LEFT"] = 4)] = "LEFT"; })(Direction || (Direction = {})); var dir = Direction.UP;
  • 通过函数方式赋值。声明枚举初始值时,可以通过函数返回的值赋值。注意,一旦其中一个枚举值通过函数方式赋值,则剩余所有参数的枚举值不能没有初始化的值,否则就会报Error
复制代码
1
2
3
4
5
6
7
8
9
10
funciton getVal(): number { return 1; } enum Direction { Up = getVal(), Right = getVal(), Down, // ERROR,这里不能不赋予初始枚举值 Left = getVal(), }
  • ii. 字符串枚举
    字符串枚举没有自增长的行为,每个枚举值都必须用字符串字面量进行赋值。
复制代码
1
2
3
4
5
6
7
enum Direction { Up = "UP", Right = "RIGHT", Down = "DOWN", Left = "LEFT" }
  • 如果不对枚举值进行字符串字面量赋值,则枚举值会默认以数值枚举值进行自增长行为。
  • 一旦使用字符串枚举,则所有的值都要有初始值,否则会报错。
复制代码
1
2
3
4
5
6
7
enum Direction { Up = "UP", Right = "RIGHT", Down = "DOWN", Left // ERROR,需要有初始值 }
  • iii. 异构枚举
    Enum支持枚举成员可以是number又可以是string,但不建议这样做。因为实际上这么做没有什么意义,除非万不得已不建议这样操作。建议还是声明同种类型的枚举值。
复制代码
1
2
3
4
5
6
7
8
9
10
enum Check { No = 0, Yes = "YES" } // ES5 (function (Check) { Check[Check["No"] = 0] = "No"; Check["Yes"] = "YES" })(Check || (Check = {}))

1.7 Any类型

Typescript中,任何类型都可以被归为Any类型。这让Any类型成为了类型系统的顶级类型(也被称为全局超级类型)。

复制代码
1
2
3
4
let notType: any = 666; notType = "张三"; notType = false;

Typescript允许我们对它执行任何操作,无需执行事先任何形式的检查:

复制代码
1
2
3
4
5
6
7
let value: any; value.foo.bar; value.trim(); value(); new value(); value[0][1];

但这其实并不符合Typescript设计的初衷,尤其是无法使用系统提供的大量保护机制,所以一般很少用到。

1.8 Unknown类型

Unknown是系统的另一种顶级类型,所有类型的值都可以赋值给Unknown

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
let value: unknown; value = true; value = 42; value = "Hello World"; value = []; value = {}; value = Math.random; value = null; value = undifined; value = new TypeError(); value = Symbol();

但不可将Unknown的值赋值给其他类型的变量,除了Any类型和他同种类型的变量。

复制代码
1
2
3
4
5
6
7
8
9
10
let value: unknown; let value1: unknown = value; let value2: any = value; let value3: boolean = value; // ERROR let value4: number = value; // ERROR let value5: string = value; // ERROR let value6: object = value; // ERROR let value7: any[] = value; // ERROR let value8: Function = value; // ERROR

此外,Unknown类型的值不可以进行其他操作。

复制代码
1
2
3
4
5
6
7
let value: unknown; value.foo.bar; // ERROR value.trim(); // ERROR value(); // ERROR new value(); // ERROR value[0][1]; // ERROR

value的变量类型设置为Unknown之后,这些操作都不再被认为是类型正确的。通过将Any类型改变为Unknown类型,我们可以将本来允许更改的配置,改为禁止任何更改

1.8 Tuple类型

元组类型。TypeScript的数组一般由同种类型的值组成,如果要在单个变量中储存不同类型的值,这时候我们可以使用元组。

复制代码
1
2
3
let tupleType: [string, boolean]; tupleType = ["张三", true];

使用元组时,每一个属性都有一个关联的类型,必须提供每个属性的值,如果出现类型不匹配或没有值,则会报错 。我们可以通过下标的方式访问元组中的元素:

复制代码
1
2
3
4
5
6
let tupleType: [string, boolean]; tupleType = ["张三"]; // ERROR,第二个值不能为空 tupleType = ["123"]; // ERROR,类型不匹配 console.log(tupleType[0]); // 张三 console.log(tupleType[1]); // true

1.9 Void类型

Void类型与Any类型相反,表示没有任何类型。当一个函数没有返回值时,可以将函数类型设置为该类型:

复制代码
1
2
3
4
5
6
7
8
9
function warnUser(): void { console.log("warning!"); } // ES5 "use strict"; function warnUser() { console.log("warning!"); }

注意,声明一个void类型的变量没有任何作用,在严格模式下,该变量的值只能为undifined

复制代码
1
2
let unusable: void = undefined;

1.9 Null和Undifined类型

Null类型:

复制代码
1
2
let n: null = null;

Undifined类型:

复制代码
1
2
let u: undefined = undefined;

注意,两者互不相通,跟JavaScript保持一致。

1.10 object,Object,{}类型

  • i. object类型
    object类型表示任何非原始(基本类型)值的类型,包括对象、函数和数组等
复制代码
1
2
3
4
5
6
7
let a: object; a = {}; // OK a = [1, 2, 3]; // OK a = [1, true, "张三"]; // OK a = () => 1; // OK a = 66; // ERROR,不能将类型number分配给类型object
  • 对于JavaScript而言,只有(大)Object,没有(小)object,(小)object只是typeof判断类型返回的一个字符串而已。
  • 例如,在ES6中,WeakMap要求键必须是对象,在TypeScript中定义的WeakMap使用的正是object约束键的类型:
复制代码
1
2
3
4
5
6
7
interface WeakMap<K extends object, V> { delete(key: K): boolean; get(key: K): V | undefined; has(key: K): boolean; set(key: K, value: V): this; }
  • ii. Object类型
    TypeScriptJavaScript Object拆成了两个接口来定义:
  1. interface Object接口类型,用于定义JS Object的原型对象Object.prototype
复制代码
1
2
3
4
5
6
7
8
9
10
interface Object { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: PropertyKey): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: PropertyKey): boolean; }
  1. interface ObjectConstructor接口类型用于定义Object的自身属性,如Object.create()
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface ObjectConstructor { new(value?: any): Object; (): any; (value: any): any; readonly prototype: Object; getPrototypeOf(o: any): any; getOwnPropertyNames(o: any): string[]; create(o: object | null): any; defineProperty<T>(o: T, p: PropertyKey, ...): T; freeze<T>(a: T[]): readonly T[]; freeze<T extends Function>(f: T): T; freeze<T>(o: T): Readonly<T>; // ... }
  1. Object的所有实例都继承了Object接口的所有属性和方法:
复制代码
1
2
3
4
function f(x: Object): { toString(): string } { return x; // OK }
  1. object类型也可以访问Object接口上定义的所有属性和方法:
复制代码
1
2
3
4
let bar: object = {}; bar.toString(); // "[object Object]" bar.hasOwnProperty("abc"); // false
  1. 有趣的是,由于JavaScript的装箱拆箱机制,基本类型有能力访问Object.prototype原型对象上的属性。因此,在TS Object类型可以同时接受引用类型和基本类型(不包括undefinednull)。但object类型不能接受原始值。
复制代码
1
2
3
let b: Object = 1; // OK let h: object = 1; // ERROR
  • iii. { }
  1. {}描述一个没有成员的对象,试图访问它的任何属性的时候,TS都会抛出错误。该类型也可以访问Object类型上的所有属性和方法:
复制代码
1
2
3
4
const obj: {} = {}; console.log(obj.name); // ERROR,没有这个属性 obj.toString(); // "[object, Object]"
  1. {}也可以被赋予一个初始值:
复制代码
1
2
3
let obj: {}; obj = 3; // OK
  1. 虽然Object{}都可以接受基本类型的值,但不包括nullundefined
复制代码
1
2
3
let obj: {} = null || undefined; // ERROR let obj: Object = null || undefined; // ERROR

总结,从严谨程度上说,object > Object > {}。前两者不能赋值给{}Object是宽泛通用的,{}是宽泛,但并不完全通用的类型。object是最严谨的类型,经常用来约束变量。
从权限程度上说,{} > object > Object。前两者(包括其他基本类型)由于拆装箱机制的存在,可以访问到Object的原型属性。object可以访问到除了基本类型的值以外的属性。但{}完全不能访问。
因此,在约束对象类型的时候,应该始终使用object。我们在定义对象类型的时候,应该多使用{}。尽可能少的去使用Object

1.11 Never类型

Never类型表示那些永不存在的值的类型。例如,Never类型是那些总会抛出异常或根本就不会有返回值的函数表达式的返回值的类型:

复制代码
1
2
3
4
5
6
7
function error(message: string): never { throw new Error(message); } function infiniteLoop(): never { while(true) {} }

TS中,我们可以利用never类型的特性来实现全面性检查:

复制代码
1
2
3
4
5
6
7
8
9
10
11
type IsStrNum = string | number; function controlFlowAnalysisWithNever(str: isStrNum) { if (typeof str === "string") { // 收窄为 string 类型 } else if (typeof str === "number") { // 收窄为 number 类型 } else { const result: never = str; } }

注意在else分支里面,我们把收窄为neverstr赋值给一个显示声明的never变量。如果一切逻辑正确,那么这里应该能够编译通过。但是假如后来有一天你的同事修改了IsStrNum的类型:

复制代码
1
2
3
4
type IsStrNum = string | number; => type IsStrNum = string | number | boolean;

然而他忘记同时修改controlFlowAnalysisWithNever方法中的控制流程,这时候else分支的str类型会被收窄为boolean类型,导致无法赋值给never类型,这时就会产生一个编译错误。通过这个方式,我们可以确保controlFlowAnalysisWithNever方法总是穷尽了IsStrNum的所有可能类型。 通过这个示例,我们可以得出一个结论:使用never避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。

至此,关于TypeScript基础篇的基础数据类型就写到这里,看到这里给大家抛出一个疑问:TypeScript总共有多少种数据类型?评论区留下你的答案。

最后

以上就是花痴橘子最近收集整理的关于TypeScript ---- 初识基础篇TypeScript ---- 初识基础篇的全部内容,更多相关TypeScript内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(68)

评论列表共有 0 条评论

立即
投稿
返回
顶部