typesctipt学习总结
1,开始之前
开始之前 全局安装ts
npm i -g typescript
-
想运行.ts的文件 必须先编译 eg: tsc Tsdemo.ts 会得到 Tsdemo.js
-
TS的编译插件 TypeScript Hero
-
typescript local zh-Cn:报错提示中文 不建议使用 方便百度报错信息
-
ts的配置文件
-
tsc --init 生成tsconfig.json文件
-
target:ES5 ES2015
-
target是ts编译后的语法
-
module:Ts的模块化方式
-
outDir:编译结果存放的目录
-
rootDir:源代码的存放目录
-
sourceMap:开启源代码映射
-
strict:开启严格模式 严格模式:必须严格配置类型 不会被隐式转成any类型 完全匹配
-
strictNullChecks:检测变量不能为空
-
lib:标准库 会覆盖源码库 注意! 标准库:内置对象的声明库
2,数据类型
-
Ts的原始类型: => js的基础类型.
-
严格模式下不允许原始类型数据为null 非严格模式下可以
-
number string 布尔 null undefind
-
Symbol()独一无二的值
列子
let num: number = 10; // number 包括NaN infinity
// num='str' error => num不能给string类型所定义
let str: string = '1'
let flag: boolean = true
// void只能存放 null或undefined 严格模式下只能是undefined
let vi: void = undefined
let sy = Symbol()// ES6新增 Symbol()独一无二的值 target:es5 会报错
原始值
原始值呢 就是js的数据类型 number string boolean null undefined 其中ts也对基本数据类型做了一个扩展 加入了 void(空值),any(任意值),tuple(固定数组长度),never(没有值,不能是任何值).enum(枚举)
ps:void跟null跟undefined的区别就是在于,null和undefined可以赋值给变量不会报错 而void赋值给变量的话会报错
任意值any
any的话就是代表任意值,当我们定义一个函数或者对象不确定里面的数据类型的时候就可以使用any来表达,或者声明变量未指定类型也会被类推论成any类型,官方文档呢是不建议使用any的 因为这样的写的话很爽,跟写js一样,缺点呢就是emm你都这样写了还不如直接写js了。
类型推论
什么是类型推论?
简单说呢,就是你声明了一个变量 并且没有声明类型,那么这个时候会被ts类推论为any 但是在你使用的时候赋值给了这个变量了,那么ts就会根据你赋值数据类型推论出你的这个变量的类型。
ps:如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:
类型推论
就是声明了一个变量但是没有指定数据类型,这个时候ts就是会根据赋值的类型推论出这个变量的数据类型
ps: 如果声明了变量没有赋值的话 那就会被推论成any 不管你是否后面赋值或者重新赋值 它的数据类型都会是any
eg:
let my='tom';
// my=8000 // 不能将类型“number”分配给类型“string”。
let tom;
tom='tom'
tom=6000
联合类型
联合类型就是在声明变量的时候可以给他指定多个类型中的一种,简单的理解呢就是有点像三元表达式,不过他使用的也是|符号
eg:
let test:number|string|boolean;
test=6; //不会报错
test='报错是不可能报错的' //不会报错
test=true //不会报错
test=object //找不到名称“object”。你是否指的是“Object”?
//这里就报错了 因为指定的类型中没有object
对象类型–接口
怎么理解接口这个概念呢,官方的解释呢就是对对象的行为的抽象,而具体的行动是需要类去实现。
是不是理解起来还是有点懵。好吧简单的说呢 就是你提前定义好的一个对象 然后这个对象的结构是什么样的 比如有哪些属性,属性是哪些数据类型
有哪些方法这些都是你提前定义好的。那么我们要通过类来生成你这个实例的时候呢 就必须按照你定义好的这些方法来用。
这里提供属性
Interfaces 通过这个关键字来定义接口
?可选属性 比如我们定义了3个属性 实际我只需要用到两个的时候,给多给少都会报错。这个时候就可以用可选属性
[propName: string]: any; 任意属性 就是当我们需要自由的往对象里面添加属性的时候就可以用这个
readonly 只读属性 表示只可以读,不可以后续修改和赋值 注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:
eg:
interface Person { //定义接口
readonly id:number // 只读属性
name:string
age?:number //可选属性
[gender:string]:any //任意属性
}
let tom:Person={
id:1,
name:'tom',
gender:'男',
sehei:'你好吗',
title:'独善其身',
}
数组的类型
数组的类型
数组定义的方式
类型 + 方括号表示法
数组泛型
用接口表示数组 ps:比较麻烦所以用得少
类数组 用来在一些伪数组上
在数组定义的时候会给数组指定类型,如果不指定ts会根据类推论来隐式确定数组的数据类型。如果希望数组类型中可以是任意类型的时候可以使用any来指定数组的类型。
eg:
let arr:number[]=[12,23,32,12,21,33] //类型 + 方括号表示法
// arr.push('22') //类型“string”的参数不能赋给类型“number”的参数。
let arr2:Array<number>=[55,77,56,98,45] //数组泛型
函数类型
除了js函数表达式和函数声明创建外 在ts的创建方式如下
可以用接口定义函数的形状
可以用?号在设置可选参数,注意可选参数需要放在必选参数的后面
参数默认值 这个在es6就加入了 在ts中会把参数默认值视为可选参数 不过参数默认值就不会受可选参数必须写在必选参数后面的影响
剩余参数 ES6 中,可以使用 …rest 的方式获取函数中的剩余参数(rest 参数)
函数重载其实就是: 多个函数函数名相同,函数的参数类型,顺序,个数不同。注意函数重载与返回值类型无关。
eg:
// 接口定义函数的形状
interface SearchFunc{
(num1:number,num2:number,optional?:number):number
}
let fn:SearchFunc;
fn=function(num1:number,num2:number,num3?:number){
return num1+num2
}
// 剩余参数案例
function push(array,...items){
items.forEach(item=>{
return item
})
return items
}
// 函数重载
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
类型断言
语法:值 as 类型 或 <类型>值
主要的作用就是:
1,联合类型可以被断言成其中的一个类型
2,父类可以断言成子类
3,任何类型可以被断言成any
4,any可以断言成任何的类型
需要注意的是类型断言只能欺骗ts编译器,不会改变实际运行中代码的错误,所以不建议滥用啦
类型别名
就是通过type给类型起一个别的名字 之后要用的时候直接调用这个别名就可以了
不过类型别名跟interface又是什么区别呢?
类型别名只是给类型取了一个名字 并不是创建一个新的类型。要创建类型还是得要interface 。
eg:
type str=string;
let a:str;
a='张三'
// 字符串字面量类型
// 用来规定取值范围
eg:
type EventNames = 'click' | 'scroll' | 'mousemove';
元组
元组的作用就是把数据类型放在一个数组中 然后通过下标来取。
eg:
let tom:[string,number];
tom[0]='123'
tom[1]=123
// 这里必须得按照下标来 如果是下标为string赋值是number或者其他类型的话就会报错
// ps:当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:
枚举
枚举类型 一个特殊的数组 一般用来定义一些不常变的状态
enum xxx{}
enum定义枚举的关键字
使用的时候和对象类似eg:State.Mr => 得到0
枚举类型会入侵运行时代码 => emmm…怎么解释?:=>枚举类型会影响编译的结果,
最后会编译成一个类似map的双向键值对对象.ts在编译的时候会进行类型注解然后删除 枚举不会
通过索引器的方式(键)可以访问枚举的值eg:State[0]=>Mr。
enum State {
Mr = 2,// 先生
Ms // 女士 Ms=3 这里因为Mr=2 所以会从1开始计算
}
// 可以不定义枚举中的值,默认从0开始累加
enum State1 {
Mr,// 先生
Ms // 女士
}
// 字符串枚举 必须手动给成员添加值
enum State2 {
Mr = '先生',// 先生
Ms = '女士' // 女士
}
// 常量枚举 编译时枚举会被删除,在编译时会指定具体的值,其余的状态会以注释的状态存在
const enum State3 {
Mr = '先生',// 先生
Ms = '女士' // 女士
}
// 枚举还有常数项和计算所得项,以上的都是常数项
// 计算所得项eg:
enum Color {Red, Green, Blue = "blue".length};
// ps:计算所得项后面就不能在写常数项了,要不然会报错
// 常数枚举 和外部枚举
// 常数枚举;使用const emun 定义的枚举类型
eg:
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
// 常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员。
// 外部枚举(Ambient Enums)是使用 declare enum 定义的枚举类型:
类与接口
类是es6的新特性
什么叫做类?
引用官方的回答就是,定义一件事物的抽象特点,包含它的属性和方法
比如说,手机是一个类,手机中有华为手机,小米手机。那么不同品牌的手机都有他们各自的属性和方法
我们可以定义一个手机的类,并给这个类属性和方法,因为都是手机肯定都是有哪些属性哪些方法是一样的,然后在通过new关键字来生成一个具体的手机品牌实例
在这个实例中就可以具体哪些品牌手机有哪些具体的属性和方法啦
class定义类,constructor定义构造函数
new生成实例会自动调用构造函数
extends 实现继承 子类继承使用super
存取器 是两个方法 存set 取get。
// 修饰符:
// static 静态方法 使用静态方法就可以不用实例而直接通过类调用
class Animal {
static isAnimal(a) {
return a instanceof Animal;
}
}
let a = new Animal('soap');
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function
// `public` 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 `public` 的
// `private` 修饰的属性或方法是私有的,不能在声明它的类的外部访问
// `protected` 修饰的属性或方法是受保护的,它和 `private` 类似,区别是它在子类中也是允许被访问的
抽象类
一开始看到这个以为很难,其实了解后也不难。抽象类就是定义一个类 这个类不能被实例化。
只能被子类继承实现。
泛型
在声明函数或者数组是不去指定特定的类型.在使用的时候再去定义类型。
// eg:
function creatArry<T>(length: number, value: T) {
let res = Array<T>(length).fill(value)
return res
}
const Arr = creatArry<string>(3, '1')
const Arr1 = creatArry<number>(3, 1)
以上所有学习资料来源于 https://ts.xcatliu.com/