一、ts概念
1. 什么是ts
-
原理
ts是js的一个超集,在js原有的语法上,添加了可选静态类型和基于类的面向对象编程
-
项目
- ts:面向解决大型复杂项目,多人协同架构及代码维护复杂的场景
- js:脚本化语言,面向相对简单的单页面场景
-
自主检测
- ts:编译期间,主动发现并纠正提示错误 ⇒ 执行前检测
- js:运行时报错
-
类型检测
- ts:弱类型,编译时支持动态和静态类型检测
- js:弱类型,无静态类型选项
-
运行流程
- ts:依赖编译,打包实现并转义成浏览器可运行的代码
- js:可以直接被浏览器运行
-
复杂特性
- ts:模块化、泛型、接口
2. 安装运行
npm install -g typescript
tsc -v
tsc ./test.ts
面试点
-
所有的类型检测和纠错阶段
编译时
二、ts基础类型与写法
- boolean
- string
- number
- array
- null
- undefined
// js
let editable = true;
let text = 'hello world';
let num = 2;
let u = undefined;
let n = null;
let arr = ['basic', 'execute'];
// ts
let editable: boolean = true;
let text: string = 'hello world';
let num: number = 2;
let u: undefined = undefined;
let n: null = null;
let arr: string[] = ['basic', 'execute'];
let arr: Array<string> = ['basic', 'execute'];
- tuple 元组
let tupleType: [string, boolean];
tupleType = ['text', true];
- enum 枚举
// 数字类型枚举 -- 默认从零开始,依次递增
enum Score {
BAD,
NG,
GOOD,
PERFECT
}
let score: Score = Score.BAD;
// 字符串类型枚举
enum Score {
BAD: 'bad',
NG: 'ng',
GOOD: 'good',
PERFECT: 'perfect'
}
// 值
enum Score {
BAD, // 0
NG,
GOOD,
PERFECT
}
// 反向映射
enum Score {
BAD, // 0
NG,
GOOD,
PERFECT
}
let scoreName = Score[0]; // BAD
let scoreValue = Score['BAD']; // 0
// 异构状态
enum Enum{
A, // 0
B, // 1
C = "C",
D = "D",
E = 6,
F // 7
}
// 面试题:指出每种具体值
// 1. 第一个未明确赋值的项目为0,所有未赋值项目依次排列,直到数字被打断
// 2. 从数字打断处,以数字作为起始值,依次排列
// 3. 有明确赋值的项目,保留赋值
// 引出 => js本质实现(手写异构枚举)
let Enum;
(function(Enum){
// 正向
Enum["A"] = 0;
Enum["B"] = 1;
Enum["C"] = "C";
Enum["D"] = "D";
Enum["E"] = 6;
Enum["F"] = 7;
// 逆向
Enum["0"] = "A";
Enum["1"] = "B";
Enum["6"] = "E";
Enum["7"] = "F";
})
-
any:绕过所有类型检测 ⇒ 类型检测、编译筛查全部失效。级别最高
let anyValue: any = 123; anyValue = 'anyValue'; anyValue = false; let Value1: boolean = anyValue; -
unknown:绕过赋值检查 ⇒ 禁止更改传递
let unknownValue: unknown; unknownValue = true; unknownValue = 123; let value1: unknown = unknownValue; // 合法 let value2: any = unknownValue; // 合法 let value3: boolean = unknownValue; // 不合法 -
void:与any相反,用于声明返回值 ⇒ 会结束,但没有返回值
function voidFunction(): void{ console.log('void function'); } -
never:永不返回,永远error
function error(msg: string): never{ throw new Error(msg); } function longlongloop(): never{ while(true){ ... } }
三、对象
-
object:非原始类型
ts将jsObject分成两个接口定义interface ObjectConstructor{ create(o: object | null): any; } const proto = {}; Object.create(Proto); // 合法 Object.create(null); // 合法 Object.create(undefined); // 不合法 -
Object
Object.prototype上的属性interface Object{ constructor: FUnction; toString(): string; valueOf(): object; hasOwnProperty(v: PropertyKey): boolean; isPrototypeOf(v: object): boole }定义了Object类属性
interface ObjectConstructor{ new(value: any): object; readonly prototype: Object; } -
{}:定义空属性
优点:防止新属性添加紊乱
cons tobj = {}; obj.class = 'text'; // Error const obj = {}; obj.toString(); // Ok
四、接口(interface
-
对行为的抽象,具体行为实现由类实现
// 描述对象的内容,不实现具体逻辑 interface Class{ name: string; time: number } let text: Class{ name: "typeScript", time: 2022 } -
只读
interface Clas{ readonly name: string; time: number; }
面试题
-
和js引用的不同 ⇒ const
let arr: number[] = [1, 2, 3, 4]; let ro: ReadonlyArray<number> = arr; ro[0] = 2; // 赋值 Error ro.push(5); // 增加 Error ro.length = 100; // 修改长度 Error arr = ro; // 覆盖 Error -
任意可添加属性
interface Class{ readonly name: string; time: number; [propName: string]: any // 可任意添加属性 } const c1 = {name: "js"}; const c2 = {name: "browser", time: 2022, level: 1}; const c3 = {name: "typescript", time: 2023, isTrail: true};
五、交叉类型(&)
interface A { x: D };
interface B { x: E };
interface C { x: F };
interface D { d: boolean };
interface E { e: string };
interface F { f: number };
type ABC = A & B & C;
let abc: ABC = {
d: false,
e: "text",
f: 5
}
面试题
-
合并冲突问题
interface A { c: string; d: string; } interface B { c: number; e: string; } type AB = A & B; let ab: AB = { d: 'class', e: 'text' } // 合并关系是且 => c: never
六、断言(类型声明、转换)(对编译器的告知交流)
-
编译时作用
// 尖括号形式声明 -- 阶段性类型 let anyValue: any = 'value'; let anyValue: number = (<string>anyValue).length; // AS 声明 let anyValue: any = 'value'; let anyLength: number = (anyValue as string).length; // 非空判断 -- 只确定不是空 type ClassTime = () => number; const start = (classTime: ClassTIme | undefined) =>{ let num = classTime!(); // 具体类型待定,但确定非空 }面试题
const tsClass: number | undefined = undefined; const test: number = tsClass!; console.log(test); // 编译时通过 'use strict' const tsClass = undefined; const test = tsClass; console.log(test); // undefined存在的意义是?
肯定断言 — 肯定化保证赋值
let score!: number; startClass(); console.log(2 * score); function startClass(){ score = 5; } // let score!: number -- 告知编译器,运行时,会被赋值的
七、类型守卫 — 保障在语法规定的范围内,额外的确认
-
多态:多种状态(多种类型)
// in -- 定义属性场景下的内容确认 interface Teacher{ name: string; courses: string[]; } interface Student{ name: string; startDate: Date; } type Class = Teacher | Student; function startCourse(cls: Class){ if('courses' in cls){ console.log('i m teacher'); } if('startTime' in cls){ console.log('i m student'); } } // typeof / instanceof -- 类型分类场景下的身份确认 // typeof function class(name: string, score: string | number){ if (typeof score === 'number') { console.log('teacher'); } if (typeof score === 'string') { console.log('student'); } } // instanceof interface Teacher{ name: string; courses: string[]; } interface Student{ name: string; startDate: Date; } type Class = Teacher | Student; const getName = (cls: Class) => { if (cls instanceof Teacher) { return cls.courses; } if (cls instanceof Student) { return cls.name; } } // 自定义类型 const isTeacher = function (cls: Teacher | Student): cls is Teacher { return 'courses' in cls; } const getName = (cls: Teacher | Student) => { if (isTeacher(cls)) { return cls.courses; } }
八、ts进阶
1. 函数重载
class Class {
start(name: number, score: number): number;
start(name: string, score: string): string;
start(name: Combinable, score: Combinable) {
if (typeof name === 'string' || typeof score === 'string') {
return 'student' + name + score;
}
return 'teacher' + name + score;
}
}
2. 泛型 — 重用
-
让模块可以支持多种类型的数据 — 类型和值一样可以赋值传递
function startClass<T, U>(name: T, score: U): T { return name + score; } function startClass<T, U>(name: T, score: U): string { return `${name}${score}` } function startClass<T, U>(name: T, score: U): T { return (name + String(score)) as any as T; } startClass<Number, String>('yy', 5);
3. 装饰器 — decorator
function test(target: Function): void{
target.prototype.startClass = function(): void{
// startClass
}
}
@test
class Class{
//......
}
// 属性装饰器
function nameWrapper(target: any, key: string) {
// ......
Object.defineProperty(target, key, {
// getter & setter
})
}
class Class {
@nameWrapper
public name: string;
}