基础知识
TS优缺点
TS优点
- 跨平台
- ES6特性
- 静态类型检查
- 面向对象的语言,如类、接口、继承、泛型等
缺点
- 需要长时间编译代码
- 不支持抽象类
严格模式
通过在tsconfig.json中设置“strict”:true,开启TS的严格模式,会让编译器对类型检查更严格,减少运行时错误。
TS的内置数据类型
- number:数字类型,TS中的所有数字都存储为浮点值
- string:字符串类型
- boolean:布尔类型
- null:显式赋值,但没有值
- undefined:已声明但未赋值的变量
- void:不返回任何类型值的函数的返回类型
TS的联合类型
联合类型:表示取值可以为多种类型中的一种
let a:string | number
a = 'test'
a = 1
TS的接口---interface
接口:定义了行为和动作规范。
对象类型接口,下次定义同类型参数时就可以复用类型
interface Person{
name:string;
age?:number; // 可选属性
readonly x:number; // 只读属性,只有初始化的时候可以修改其值
[key:string]:any;//可以无限扩展属性
fn():void;// 也可以定义方法
}
const student = ({name}:Person):string =>{}
⚠️可选属性如果没有赋值,则获取到的值是undefined,对于可选方法,必须先进行判断,再调用,否则会报错。
const p:Person ={
if(p.fn){
p.fn()
}
}
函数类型接口。通过interface限制函数的参数类型和返回值类型
interface ComFunc{
(source:string,subString:string):boolean
}
let fun:ComFunc;
fun = function(source:string,subString:string){
}
接口可以合并
interface One {
color:string;
name:string;
}
interface One{
age:number
}
const Two:One = {
color:'red';
name:'test';
age:12;
}
接口可以继承,用extends,多个合并,用,隔开
interface One {
color:string;
name:string;
}
interface OneByOne extends One{
age:number
}
const Two:OneByOne = {
color:'red';
name:'test';
age:12;
}
TS 中的type(类型别名)
TS的interface与type的不同
相同点
- 都可以描述一个对象或者函数
- 都可以扩展
不同点
- type可以修饰任何类型(值类型和引用数据类型),interface只能修饰引用类型(对象,数组,函数)
- type语句中可以使用typeof获取实例的类型进行赋值
- type可以使用in关键字生成映射类型,interface不行
- interface具有合并能力(同名的接口会自动合并一个接口),type不具有合并能力
TS的类
//最基本的语法
class className {
属性
构造函数
方法
}
修饰符
class Person {
public name:string; //类中、子类内的任何地方、外部都能调用
protected age:number; // 类中、子类内的任何地方都能调用,但外部不能调用
private tel:number; // 类中可以调用,子类内的任何地方、外部都不能调用
}
abstract
用abstract关键字声明的类叫做抽象类,声明的方法叫抽象方法。
- 抽象类:指不能被实例化,因为它立main包含一个或多个抽象方法。
- 抽象方法:指不包含具体实现的方法。 ⚠️:抽象类是不能直接实例化,只能实例化实现所有抽象方法的子类。
abstract class Person {
constructor(public name:string){}
// 抽象方法
abstract setAge(age:number):void;
}
class Child extends Person {
constructor(name:string){
super(name)
}
setAge(age:number):void{
console.log(`名字是${this.name},年龄是${age}`)
}
}
let res = new Person('test') // error
let res1 = new Child('tom')
res1.setAge(12) // 名字是tom,年龄是12
重写、重载
- 重写:子类重写继承自父类中的方法
- 重载:指为同一个函数提供多个类型定义,与上述函数的重载类似
// 重写
class Person {
setName(name:string){
erturn `我的名字叫${name}`
}
}
class Child extends Person {
setName(name:string){
return `你的名字叫${name}`
}
}
const yourName = new Child()
console.log(yourName.setName('tom')) // "你的名字叫tom"
// 重载
class Person1{
setNameAge(name: string):void;
setNameAge(name: number):void;
setNameAge(name:string | number){
if(typeof name === 'string'){
console.log(`我的名字是${name}`)
}else{
console.log(`我的年龄是${name}`)
}
};
}
const res = new Person1()
res.setNameAge('小杜杜') // "我的名字是小杜杜"
res.setNameAge(7) // "我的年龄是7"
TS迭代器
背景
从一个数据集中获取一个数据项,对这个数据集进行迭代
(用于处理集合数据【数组、对象】的工具)可以通过 for…of 循环、扩展运算符、解构赋值等方式来使用迭代器。
定义
迭代器是一个对象,它定义了一个序列,提供一种方法访问这个序列的元素,迭代器对象实现了Iterator接口,返回一个next()方法
使用场景
使用方法
迭代器是一种特殊对象,迭代器对象上有个next方法, 每次调用next()方法都会返回一个对象{value:'', done:false}, 其中value属性是每次迭代的值, done属性是一个布尔值, 判断当前是否迭代完毕, 迭代完成后,返回true
生成器
TS的命名空间
命名空间:解决重名问题,定义了标识符的可见范围
// TS中命名空间使用namespace定义,语法格式如下
namespace Test{
export interface Person{
name:string = 'one'
}
export class Student{}
}
console.log(Test.Person.name) // one
可以通过<reference path="xxx.ts"/>导入已存在的命名空间
// one.ts
namespace Food {
export interface Fruits {
name:string;
}
}
// two.ts
<reference path="one.ts"/>
let fruits:Food.Fruits
TS的模块
import、export
TS的命名空间与模块的区别
- 命名空间:内部模块,主要是防止命名冲突
- 模块是TS外部模块的简称,侧重于代码的复用
- 一个模块里可能会有多个命名空间
TS的断言
TS断言分为三种:类型断言、非空断言、确定赋值断言
类型断言
在特定的环境中,具体是什么类型,不需要TS去判断。 共有两种方式:
- 「尖括号」
- 「as」:推荐使用
// 尖括号
let num:any = 'tom'
let res1:number = (<string>num).length; // react会报错
// as语法
let str:any = 'tom'
let res:number = (str as string).length
非空断言
在上下文中当类型检查器无法断定类型时,出现一个新的后缀表达式操作符!可以用于断言操作对象是「非null和非undefined类型」
function test(a:number | undefined){
const b:number = a; //error:undefined is not assignable to number
const c:number = a!;//ok
}
确定赋值断言
允许在实例属性和变量声明后面放置一个!号,告诉TS该属性会被明确赋值。
let num:number;
let num1!:number;
const setNumber = () => num = 12
const setNumber1 = () => num1 = 12
setNumber()
setNumber1()
console.log(num) // error
console.log(num1) // ok
TS的类型守卫
类型守卫是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。 常见的四种类型守卫:「in关键字」,「typeof关键字」,「instanceof」,「类型谓词(is)」
in 关键字:用于判断这个属性是哪个里面的
interface Info{
name:string;
age:number;
}
interface Info1{
name:string ;
flage:true
}
const setInfo = (data:Info | Info1)=>{
if("age" in data){
console.log(`名字是${data.name},年龄是${data.age}`)
}
if("flage" in data){
console.log(`名字是${data.name},性别是${data.flage}`)
}
}
setInfo({name:'tom',age:12}) //名字是tom,年龄是12
setInfo({name:'test',flage:true}) //名字是test,性别是true
typeof关键字。用于判断基本类型
const setInfo=(data:number | string |undefined)=>{
if(typeof data === 'string'){
console.log(`名字是${data}`)
}
if(typeof data === 'number'){
console.log(`年龄是${data}`)
}
}
setInfo('tom')//名字是tom
setInfo(12)//年龄是12
instanceof关键字 用于判断一个实例是不是构造函数,或使用类的时候
class Name{
name:string= 'tom'
}
class Age extends Name {
age:number = 12
}
const setInfo = (data:Name)=>{
if(data instanceof Age){
console.log(`我的年龄是${data.age}`)
}else {
console.log(`我的名字是${data.name}`)
}
}
setInfo(new Name()) // 我的名字是tom
setInfo(new Age()) //我的年龄是12
类型谓词 is
function isNumber(x:any):x is number {
return typeof x === 'number'
}
console.log(isNumber(12))// true
console.log(isNumber('12')) // false
TS内置的常用工具类型
typeof 操作符用来获取一个变量声明或对象的类型
keyof 用于获取某种类型的所有键,返回类型是联合类型
interface Person {
name:string;
age:number;
}
type K1 = keyof Person; // "name" | "age"
in 遍历枚举类型
infer 条件类型语句中,可以用infer声明一个类型变量并且对它进行使用
extends 关键字添加泛型约束
Omit:Omit<T,U>从类型T中剔除U中的所有属性(Omit<Type,keys>)
泛型
泛型:Generics,是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用时再指定类型的一种特性。泛型会保留参数类型。
泛型语法
// 基础泛型语法
function identity<T>(value:T):T {
return value
}
// 多类型传参
const calcArray = <T,U>(name:T,age:U):{name:T,age:U}=>{
const res:{name:T,age:U} = {name,age}
return res
}
const res = calcArray<string,number>('tom',12)
console.log(res) // {name:'tom',age:12}
// 泛型接口
interface A<T>{
data:T
}
const Info:A<string> = {data:'1'}
console.log(Info.data) // 1
// 泛型类
class clacArray<T>{
private arr:T[] = []
add(value:T){
this.arr.push(value)
}
getValue():T{
let res = this.arr[0]
return res
}
}
// 泛型类型别名
type Info<T> = {
name?:T
age?:T
}
const res:Info<string> = {name:'tom'}
// 泛型默认参数
const calcArray = <T = string>(data:T):T[] =>{
let list:T[] = []
}
泛型常用字母
- 「T」:代表Type,定义泛型时通常用作第一个类型变量名称
- 「K」:代表Key,表示对象中的键类型
- 「V」:代表Value,表示对象中的值类型
- 「E」:代表Element,表示元素类型
const calcArray = <T>(data:T):T[]=>{
let list:T[] = []
for(let i = 0; i<3;i++){
list.push(data)
}
return list
}
const res:string[] = calcArray<string>('d') // ok
const res1:number[] = calcArray<number>(12) // ok
type Props = {
name:string,
age:number
}
const res2:Props[] = calcArray<props>({name:'tom',age:12}) // ok
将多个ts文件合并为一个js文件
//将三个文件file1.ts file2.ts file3.ts合并到common.js文件中
tsc --outFile common.js file1.ts file2.ts file3.ts
declare,declare global是什么?
- declare是用来定义全局变量、全局函数、全局命名空间
- declare global为全局对象window增加新的属性
协变、逆变、双变、抗变
- 协变: X = Y,Y类型可以赋值给X类型的情况。X类型兼容Y类型
编译上下文
tsconfig.json的作用
- 用于标识TS项目的根路径
- 用于配制TS编译器
- 用于指定编译的文件
tsconfig.json重要字段
- files:设置要编译的文件名称
- include:设置需要进行编译的文件,支持路径模式匹配
- exclude:设置无需进行编译的文件,支持路径模式匹配
- compilerOptions:设置与编译流程相关的选项
- baseUrl:'./' //用于解析非相对模块名称的基目录
- outFile:'./' //将输出文件合并为一个文件
- outDir:'./' //指定输入目录
装饰器
装饰器是一种特殊类型的声明,它能过被附加到类声明,方法,属性或者参数上,可以修改类的行为
通俗的来说就是一个方法,可以注入到类,方法,属性参数上来扩展类,属性,方法,参数的功能
装饰器的分类: 类装饰器、属性装饰器、方法装饰器、参数装饰器