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");
// Number 类型
// 类型声明大小写皆可
let number: number = 10;
let number1: Number = 12;
// Boolean 类型
// boolean 值为 true 或 false
let isBool: boolean = true;
// String 类型
// 保存一个字符串
let str: string = 'hello world';
// 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; // 运行错误
声明:const sy = Stmbol()
参数:string(可选)
方法:
// 声明
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
特别注意:
// 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 类型
// 数组集合,可以通过 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 类型
// 元组允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
let tup: [string, number];
tup = ['hello', 2];
// tup = [2, 'a']; Error
// 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 是 ES6 中新的数据结构,允许存储任何类型的值,原始值或者是对象引用,但成员的值是唯一的,没有重复的值。
Set 本身是一个构造函数,用来生成Set 数据结构。Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。
Set 对象的声明:
const set = new Set()
Set 实例对象的属性:
Set 实例对象的方法:
遍历方法:
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 是 ES6 中新的数据结构,Map 对象用于保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。构造函数 Map 可以接受一个数组作为参数。
Map和Object的区别
Map 对象的声明:
const set = new Map()
const set = new Map(Array)
属性:
方法:
遍历方法:
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 类型用于表示非原始类型
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 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
// 在 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 类型
// 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;
// 使用 const、var、let 声明一个变量时,你可以选择性的添加一个类型注解,显式指定变量的类型:
let myName: string = "Sakura";
// TypeScript 并不使用“在左边进行类型声明”的形式,比如 int x = 0;类型注解往往跟在要被声明类型的内容后面。
// 不过大部分时候,这不是必须的。因为 TypeScript 会自动推断类型。举个例子,变量的类型可以基于初始值进行推断:
// No type annotation needed -- 'myName' inferred as type 'string'
let myName = "Sakura.";
// 联合类型通常与 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 });