一. TS的基本概念
1、 TS的本质
是Js的一个超集,在原有的语法基础上,添加了可选的静态类型和基于类的面向对象编程
-
类型检测
js:弱类型,无静态类型选项
ts:强类型,支持动态和静态类型的检测和拦截
-
自主检测
js:runtime, 报错
ts:编译期间,主动发现并报出错误
-
运行流程
js:直接在浏览器中运行
ts:依赖编译,依赖工具化体系
-
面向项目
js:脚本化语言,面向单一简单的场景
ts:面相解决大型复杂应用,有利于代码设计以及维护
-
复杂特性
ts:模块化,接口,泛型
安装运行
npm install -g typescript tsc -v tsc test.ts // ts所有的类型检测,以及语法检测的阶段都是在编译时 // 面试:黑框错误是什么时候报出来的?--编译ts时报的错
2.ts基础类型及写法
boolean string number array null undefined
//es
let isEnable = true
let class = 'zhangsan'
let classNum = 2
let u = undefined
let n = null
let classArr = ['basic', 'execute']
//ts
let isEnable:boolean = true
let class: string = 'zhangsan'
let classNum: number = 2
let u: undefined = undefined
let n: null = null
let classArr: Array<string> = ['basic', 'execute']
let classArr: string[] = ['basic', 'execute']
- tuple 元组
let tupleType:[string, boolean]
tupleType = ['zhangsan', true]
-
enum 枚举
//数字类枚举,默认从零开始,从上往下依次递增 enum Score { BAD, NG, GOOD, PERFECT } let score: Score = Score.BAD; //字符串类型枚举 enum Score { BAD = 'BAD', NG = 'NG', GOOD = 'GOOD', PERFECT = 'PERFECT' } //反向映射 let score = Score.BAD let scoreName = Score[0] //BAD let scoreName = Score['BAD'] //0 //异构枚举 - 梳理字符串 => 数字 enum Enum { A, B, C = 'C', D = 'D', E = 6, F, } //面试题:指出异构的枚举值,并手写转化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' })(Enum || (Enum = {})) -
any unknown void
//any - 绕过所有的类型检查 => 类型检测和编译筛查全部失效 let anyVal: any = 123; anyVal = 'anyVal'; anyVal = false; let val1: boolean = anyVal //unknown - 绕过了赋值检查 => 禁止更改传递 let unknownVal: unknown; unknownVal = 123; unknownVal = 'unknownVal'; let val2: unknown = unknownVal //ok let val3: any = unknownVal //ok let val4: boolean = unknownVal //NOK //void - 声明函数无返回值 function voidFun(): void { console.log('void function') } //never - 函数用不返回 function error(msg: string):never { throw new Error(msg) } function longlongloop(): never { while(true) { //业务 } } -
Object | object | {} - 对象
//Object - 所有Object类的实例类型
//1.有值
//2. toString
//3.值的对象属性与Object接口中属性冲突时,TSC会提示错误
function fun1(x: Object){
}
fun1({
name: 'zhangsan'
})
const obj1: Object = {
toString() {
return 'zhangsan'
}
}
//object - 表示非原始类型
//1. 没有值
//2.不具备hasOwnProperty
//3.如果值对象属性与Object接口中属性冲突,TSC不会提示错误
//空对象 {} - 描述一个没有任何成员的对象,
//在赋予属性前,任何访问该对象任意属性的操作,都会被tsc编译抛出错误
const obj = {}
obj.name = 'zhangsan' //prop does not exist on type {}
二、接口-interface
- 对行为的一种抽象,具体的行为由类实现
interface Class {
name: string;
time: number;
}
let if: Class = {
name: 'ts',
time: 2
}
//只读 & 任意
interface Class {
readonly name: string;
time: number;
}
//面试题 - 只读和es中的引用是不同的
//const
let arr: number[] = [1,2,3,4]
let ro: ReadOnlyArray<number> = arr
//对ro进行任何操作,都会报ERROR
interface Class {
readonly name: string;
time: number;
[propName: string] : string | number;//不限制添加
}
三、交叉类型 - &
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 = {
x: {
d: false,
e: 'zhangsan',
f: 5
}
}
//合并冲突
interface A {
c: string,
d: string
}
interface B {
c: number,
e: string,
}
type AB = A & B
let ab: AB = {
d: 'class',
e: 'zhangsan'
}
//c: never, 且关系
四、断言 - 类型的声明、转换(开发者和编译器的告知交流)
- 编译状态产生的声明作用
let anyVal: any = 'hi zhangsan'
let anyLen: number = (<string>anyVal).length
let anyLen: number = (anyVal as string).length
type ClassTime = () => number
const start = (classTime: ClassTime | undefined) => {
let num = ClassTime ! ()//具体类型待定,但是确认是非空
}
五、类型守卫 - 保障在语法规定的范围之内做额外的确认
interface Teacher {
name: string,
courses: string[],
score: number
}
interface Student {
name: string,
startTime: number,
score: string
}
type Class = Teacher | Student
//in - 是否包含某种属性
function startCourse(cls: Class) {
if('courses' in cls) {
//老师
}
if('startTime' in cls) {
//学生
}
}
//typeof / instanceof
function startCourse(cls: Class) {
if(typeof cls.score === 'number') {
//老师
}
if(typeof cls.score === 'string') {
//学生
}
}
class Teacher {}
class Student {}
function startCourse(cls: Class) {
if( cls instanceof Teacher) {
//老师
}
if(cls instanceof Student) {
//学生
}
}
六、TS进阶方案
1.函数重载
class Class {
start(name: number, score: number): number;
start(name: string, score: string): string;
start(name: string, score: number): number;
start(name: Combinable, score: Combinable): {
if (typeof name === 'number' && type score === 'number') {
//处理
}
if (typeof name === 'string' && type score === 'string') {
//处理
}
if (typeof name === 'string' && type score === 'number') {
//处理
}
};
}
2.泛型 - 重用
function startClass <T, U>(name: T, score: U): T{
//逻辑
}
function startClass <T, U>(name: T, score: U): string{
//逻辑
}
3.装饰器 - decorator
function Zhao (target: Function): void {
target.prototype.startClass = function (): void {
//逻辑
}
}
@Zhao
class Course {
constructor() {
//业务逻辑
}
}
//#####################################
function nameWrapper(target: string | number, key: string): void {
Object.defineProperty(target, key, {})
}
class Course {
constructor() {
//业务逻辑
}
@nameWrapper
public name: string;
}
补充
// 插入
// readonly | partial | required | omit | pick
// partial -- 可选的,不可以添加interface中不存在的属性
// required -- 必选的,
// omit
// pick -- 选择, 挑选出需要的属性
interface Class {
name: string,
time: number,
department: string
}
type newCls = Partial<Class>
// 相等于
type newCls2 = {
name?: string | undefined,
time?: number | undefined,
department?: string | undefined
}
/ type newCls = Required<Class>
// 相等于
type newCls2 = {
name?: string | undefined,
time?: number | undefined,
department?: string | undefined
}
// omit
interface Student {
name: string,
age: number,
score: number
}
// 下面两项等价,student中只选择name和score
type PickStudent = Pick<Student, 'name' | 'score'>
type OmitStudent = Omit<Student, 'age'>//忽略了age