TypeScript 类型学习

TypeScript 是 JavaScript 的超集,它扩展了 JavaScript,有 JavaScript 没有的东西,支持最新的 JavaScript 新特性,故而也包含着 JavaScript 的八大内置类型。

let str: string = "jimmy";
let num: number = 24;
let bool: boolean = false;
let u: undefined = undefined;
let n: null = null;
let obj: object = {x: 1};
let big: bigint = 100n;
let sym: symbol = Symbol("me"); 

基本数据类型

Boolean、Number、String

// Number 类型
// 类型声明大小写皆可
let number: number = 10;
let number1: Number = 12;

// Boolean 类型
// boolean 值为 true 或 false
let isBool: boolean = true;

// String 类型
// 保存一个字符串
let str: string = 'hello world';

Null、Undefined

// JavaScript 中没有空值 Void 的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数;
// 声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null;
function alertName(): void {
    alert('My name is Tom');
}

let unusable: void = 1;
// Type 'number' is not assignable to type 'void'.


// Null 和 Undefined
// TypeScript 里,undefined 和 null 两者各自有自己的类型分别叫做 undefined 和 null。 
// 和 void 相似,它们的本身的类型用处不是很大。
let u: undefined = undefined;
let n: null = null;
// 默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把null和undefined赋值给number类型的变量。
// 然而,当你指定了--strictNullChecks标记,null和undefined只能赋值给void和它们各自。 这能避免很多常见的问题。 

// 启用 --strictNullChecks
let num: number;
num = 1; // 运行正确
num = undefined;    // 运行错误
num = null;    // 运行错误

ES6 中的新类型 Symbol 和 ES11 中的 BigInt

Symbol:Symbol 是 ES6 中引入的原始数据类型,代表着独一无二的

声明:const sy = Stmbol()
参数:string(可选)
方法

  • Symbol.for(): 创建以参数作为描述的 Symbol 值,如存在此参数则返回原有的 Symbol 值(先搜索后创建,登记在全局环境)
  • Symbol.keyFor(): 返回已登记的 Symbol 值的描述(只能返回 Symbol.for() 的 key)
  • Object.getOwnPropertySymbols(): 返回对象中所有用作属性名的 Symbol 值的数组
 // 声明
 let a = Symbol();
 let b = Symbol();
 console.log(a === b); // false
 
 //Symbol.for()
 let c = Symbol.for("domesy");
 let d = Symbol.for("domesy");
 console.log(c === d); // true
 
 //Symbol.keyFor()
 const e = Symbol.for("1");
 console.log(Symbol.keyFor(e)); // 1
 
 //Symbol.description
 let symbol = Symbol("es");
 console.log(symbol.description); // es
 console.log(Symbol("es") === Symbol("es")); // false
 console.log(symbol === symbol); // true
 console.log(symbol.description === "es"); // true

BigInt:表示一个任意精度的整数,可以表示超长数据,可以超出 2 的 53次方。

特别注意:

  • Number 类型的数字有精度限制,只能安全的表示 -253-1 和 253-1 范围内的值。超出这个范围的整数,就无法精确表示了。
  • Bigint 没有位数的限制,任何位数的整数都可以精确表示。但是其只能用于表示整数,且为了与 Number 进行区分,BigInt 类型的数据必须添加后缀 n。
  • BigInt 可以使用负号,但是不能使用正号。
  • number 类型的数字和 Bigint 类型的数字不能混合计算。
// Number
console.log(2 ** 53) // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991

// BigInt
const bigInt = 9007199254740993n
console.log(bigInt) // 9007199254740993n
console.log(typeof bigInt) // bigint
console.log(1n == 1) // true
console.log(1n === 1) // false
const bigIntNum = BigInt(9007199254740993n)
console.log(bigIntNum) // 9007199254740993n

对象类型

数组(Array)

// Array 类型
// 数组集合,可以通过 type[] 或 Array 为数组内的元素指定类型
let arr1: string[] = ['a', 'b', 'c'];
let arr2: Array<string> = ['d', 'e', 'f'];

// any在数组中的应用
// 一个比较常见的做法是,用 any 表示数组中允许出现任意类型:
let list: any[] = ['sakura', 21, { website: 'https://baidu.com' }];

元组(Tuple)

// Tuple 类型
// 元组允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
let tup: [string, number];
tup = ['hello', 2];
// tup = [2, 'a'];  Error

枚举(Enums)

// Enums 类型
// 枚举类型用于定义数值集合
// 列出所有可用值,一个枚举的默认初始值为0,可以调整开始的数字
enum Role {Student = 3, Teacher, Chairman};
let role1: Role = Role.Student;
let role2: Role = Role.Teacher;
let role3: Role = Role.Chairman;
console.log(role1, role2, role3);  // 3, 4, 5

Set 对象

Set 是 ES6 中新的数据结构,允许存储任何类型的值,原始值或者是对象引用,但成员的值是唯一的,没有重复的值。
Set 本身是一个构造函数,用来生成Set 数据结构。Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。
Set 对象的声明
const set = new Set()
Set 实例对象的属性

  • size:返回 Set 实例中的成员总数

Set 实例对象的方法

  • add():在 Set 对象尾部添加一个元素。返回该 Set 对象
  • delete():移除 Set 的中与这个值相等的元素,有则返回 true,无则返回 false
  • clear():清除 Set 的所有元素
  • has():是否存在这个值,如果存在为 true,否则为 false

遍历方法

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
 let map = new Set()
 
 //set()
 map.set('a', 1)
 map.set('b', 2)
 console(map) // Map(2) {'a' => 1, 'b' => 2}
 
 //get
 map.get("a") // 1
 
 //size
 console(map.size) // 2
 
 //delete()
 map.delete("a") // true
 console(map) // Map(1) {'b' => 2}
 
 //has()
 map.has('b') // true
 map.has(1) // false
 
 //clear()
 map.clear()
 console(map) // Map(0) {}
 
 let arr = [["a", 1], ["b", 2], ["c", 3]]
 let map = new Map(arr)
 
 // keys()
 for (let key of map.keys()) {
    console.log(key); // 以此打印:a b c
 }
 
 //values()
 for (let value of map.values()) {
    console.log(value); // 以此打印:1 2 3
 }
 
 //entries()
 for (let data of map.entries()) {
    console.log(data); // 以此打印:["a", 1] ["b", 2] ["c", 3]
 }
 
 //forEach
 map.forEach((item) => {
    console.log(item)// 以此打印:1 2 3
 });

Map 对象

Map 是 ES6 中新的数据结构,Map 对象用于保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。构造函数 Map 可以接受一个数组作为参数。
Map和Object的区别

  • Map中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
  • Map的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
  • Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。

Map 对象的声明
const set = new Map()
const set = new Map(Array)
属性

  • size:返回 Map 实例中值的个数

方法

  • set(): 添加Map后的一个键值对,返回实例
  • get(): 返回键值对
  • delete(): 移除Map的中与这个值相等的元素,有则返回true,无则返回false
  • clear(): 清楚Map的所有元素
  • has(): 是否存在这个值,如果存在为 true,否则为false

遍历方法

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
 let map = new Set()
 
 //set()
 map.set('a', 1)
 map.set('b', 2)
 console(map) // Map(2) {'a' => 1, 'b' => 2}
 
 //get
 map.get("a") // 1
 
 //size
 console(map.size) // 2
 
 //delete()
 map.delete("a") // true
 console(map) // Map(1) {'b' => 2}
 
 //has()
 map.has('b') // true
 map.has(1) // false
 
 //clear()
 map.clear()
 console(map) // Map(0) {}
 
 let arr = [["a", 1], ["b", 2], ["c", 3]]
 let map = new Map(arr)
 
 // keys()
 for (let key of map.keys()) {
    console.log(key); // 以此打印:a b c
 }
 
 //values()
 for (let value of map.values()) {
    console.log(value); // 以此打印:1 2 3
 }
 
 //entries()
 for (let data of map.entries()) {
    console.log(data); // 以此打印:["a", 1] ["b", 2] ["c", 3]
 }
 
 //forEach
 map.forEach((item) => {
    console.log(item)// 以此打印:1 2 3
 });

对象(Object)

// object 类型用于表示非原始类型
let objectCase: object;
objectCase = 1; // error
objectCase = "a"; // error
objectCase = true; // error
objectCase = null; // error
objectCase = undefined; // error
objectCase = {}; // ok


// Object 类型代表所有拥有 toString、hasOwnProperty 方法的类型 
// 所以所有原始类型、非原始类型都可以赋给 Object(严格模式下 null 和 undefined 不可以)
let simpleCase: {};
simpleCase = 1; // ok
simpleCase = "a"; // ok
simpleCase = true; // ok
simpleCase = null; // error
simpleCase = undefined; // error
simpleCase = {}; // ok


// 使用object类型,就可以更好的表示像Object.create这样的API
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK

// create(42); // Error
// create("string"); // Error
// create(false); // Error
// create(undefined); // Error

// 对象类型可以指定一些甚至所有的属性为可选的,你只需要在属性名后添加一个 ?:

function getName(obj: { name: string; age?: number }): void {
    console.log(obj.name);
    console.log(obj.age);
}

getName({ name: "Sakura" });

// {} 空对象类型和 Object 一样,也是表示原始类型和非原始类型的集合
let simpleCase: {};
simpleCase = 1; // ok
simpleCase = "a"; // ok
simpleCase = true; // ok
simpleCase = null; // error
simpleCase = undefined; // error
simpleCase = {}; // ok

函数(Function)

// 参数类型注解
function sum(x: number, y: number): number {
  return x + y;
}

// 输入多余的(或者少于要求的)参数,是不被允许的:

sum(1);
// 应有 2 个参数,但获得 1 个

sum(1, 2, 3); 
// 应有 2 个参数,但获得 3 个


// 可选参数和参数默认值
function hello(name1: string, name2?: string): void {
  console.log(`hello! ${name1} ${name2 ? "and" + " " + name2 : ""}`);
}

hello("余光1", "余光2"); 
// hello! 余光1 and 余光2
hello("余光"); 
// hello! 余光


// 匿名函数
const arr = [1, 2, 3, 4];

arr.forEach((val) => {
  val.toFixed(1);
});
// ✅

arr.forEach((val) => {
  val.split("-");
});
// ❌ 类型“number”上不存在属性“split”。

任意值(Any)、未知类型(Unknown)

// Any
// 在 TypeScript 中,任何类型都可以被归为 any 类型。
// 这让 any 类型成为了类型系统的顶级类型(也被称作全局超级类型)。
let any: any = 1;
let any: any[] = [1, 'a', false];

// TypeScript 允许我们对 any 类型的值执行任何操作,而无需事先执行任何形式的检查
let value: any;

value.foo.bar; // OK
value.trim(); // OK
value(); // OK
new value(); // OK
value[0][1]; // OK

// 一般使用场景: 第三方库没有提供类型文件时可以使用 any 类型转换遇到困难或者数据结构太复杂难以定义 
// 不过不要太依赖 any, 否则就失去了 ts 的意义了


// Unknown
// 就像所有类型都可以赋值给 any,所有类型也都可以赋值给 unknown。
// 这使得 unknown 成为 TypeScript 类型系统的另一种顶级类型
let value: unknown;

value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK

// unknown 和 any 的主要区别是 unknown 类型会更加严格 
// 在对 unknown 类型的值执行大多数操作之前 我们必须进行某种形式的检查 
// 而在对 any 类型的值执行操作之前 我们不必进行任何检查
// 所有类型都可以被归为 unknown 但unknown类型只能被赋值给 any 类型和 unknown 类型本身 
// 而 any 啥都能分配和被分配
let value: unknown;

let value1: unknown = value; // OK
let value2: any = value; // OK
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


let value: unknown;

value.foo.bar; // Error
value.trim(); // Error
value(); // Error
new value(); // Error
value[0][1]; // Error

// 将 value 变量类型设置为 unknown 后,这些操作都不再被认为是类型正确的。
// 通过将 any 类型改变为 unknown 类型,我们已将允许所有更改的默认设置,更改为禁止任何更改。

空值(Void)、Never

// Void 类型
// JavaScript 没有空值 Void 的概念,在 TypeScirpt 中,可以用 void 表示没有任何返回值的函数。
function alertName(): void {
    console.log('My name is changdong');
}


// Never 类型
// never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
// 这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环)。
let a: never;
let b: number;
// a = 123; // 运行错误,数字类型不能转为 never 类型
a = (() => { throw new Error('never')})(); // 运行正确,never 类型可以赋值给 never类型
b = (()=>{ throw new Error('exception')})(); // 运行正确,never 类型可以赋值给 数字类型
// 返回值为 never 的函数可以是抛出异常的情况
function error(message: string): never {
    throw new Error(message);
}
// 返回值为 never 的函数可以是无法被执行到的终止点的情况
function loop(): never {
    while (true) {}
}

字面量类型

在 TypeScript 中,字面量不仅可以表示值,还可以表示类型,即所谓的字面量类型。
目前,TypeScript 支持 3 种字面量类型:字符串字面量类型数字字面量类型布尔字面量类型,对应的字符串字面量、数字字面量、布尔字面量分别拥有与其值一样的字面量类型,

let flag1: "hello" = "hello";
let flag2: 1 = 1;
let flag3: true = true;

变量上的类型注解(Type Annotations on Variables)

// 使用 const、var、let 声明一个变量时,你可以选择性的添加一个类型注解,显式指定变量的类型:
let myName: string = "Sakura";

// TypeScript 并不使用“在左边进行类型声明”的形式,比如 int x = 0;类型注解往往跟在要被声明类型的内容后面。
// 不过大部分时候,这不是必须的。因为 TypeScript 会自动推断类型。举个例子,变量的类型可以基于初始值进行推断:

// No type annotation needed -- 'myName' inferred as type 'string'
let myName = "Sakura.";

联合类型(Union Types)

// 联合类型通常与 null 和 undefined 一起使用
const sayHello = (name: string | undefined) => {
  console.log('hello ' + name);
};

// name 的类型是 string | undefined 意味着可以将 string 或 undefined 的值传递给sayHello 函数。
sayHello("sember");
sayHello(undefined);

// 也许在某处你想传入一个string或null或undefined,你可以使用联合类型string | null | undefined。
// 启用 --strictNullChecks
let num2: number | null | undefined;
num2 = 1; // 运行正确
num2 = undefined;    // 运行正确
num2 = null;    // 运行正确

// 配合字面量进行使用,用来约束取值只能是某几个值中的一个。
let num: 1 | 2 = 1;
type EventNames = 'click' | 'scroll' | 'mousemove';

// 当TypeScript不确定一个联合类型的变量到底是哪个类型的时候
// 我们只能访问此联合类型的所有类型里共有的属性或方法:
function getLength(something: string | number[]): number {
    return something.length;
}
// ✅
function getLength(something: string | number): number {
    return something.length;
}
// ❌ 类型“string | number”上不存在属性“length”。类型“number”上不存在属性“length”。

交叉类型

交叉类型是将多个类型合并为一个类型。通过 & 运算符可以将现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性

type Flag1 = { x: number };
type Flag2 = Flag1 & { y: string };

let flag3: Flag2 = {
  x: 1,
  y: "hello",
  henb,
};

类型别名

// 类型别名用来给一个类型起个“新”名字。例如:

type hasLen = string | number[]; // isNumber就是新名字,他可能更语义化一些
const arr: hasLen = [1];


// 又或者,常用语给一个联合类型定义自己的类型别名

type Name = string; // 字符串
type NameResolver = () => string; // 函数
type NameOrResolver = Name | NameResolver; // 联合类型

function getName(n: NameOrResolver): Name {
  if (typeof n === "string") {
    return n;
  } else {
    return n();
  }
}

function getName(obj: { name: string; age: number }): void {
  console.log(obj.name);
  console.log(obj.age);
}

const res = getName({ name: "Sakura", age: 22 });

你可能感兴趣的:(JavaScript,&,TypeScript,前端,学习,typescript)