TypeScript
1.开始TS
ECMAscript,javascript,typescript的关系
ECMAscript是js的标准,是语法规范,而TS是js的超集.
安装TS
npm i typescript -g
然后创建一个hello.ts
然后运行
tsc hello.js
然后可以看见多出了一个hello.js文件
node hello.js
优化编译
当编写一个函数的时候,去调用一个函数
function hello(a,b){
console.log(a,b)
}
hello("zhangsan","lis")
然后将这个ts转化为js,转化成功之后,ts文件报错:
-
解决TS和js的冲突问题
tsc --init 生成配置文件,在配置文件中的77行,可以先注释掉严格模式
-
自动编译
tsc --watch 一旦ts文件发生了变化就会自动去转化为js文件
-
发出错误
tsc -noEmitOnError hello.ts 当有ts有错误的时候,就不会转化为js
将严格模式的注释去除,会发现报错,这个错就是
函数的参数没有指定类型.
显示类型
参数:类型
a:string
function hello( a : string,b:Date){
console.log(a,b)
}
hello("wangwu",new Date())
降级编译
ts是ES6的,怎么降级?
在tsconfig.json中
“target”: “es5”
严格模式
每个人的严格模式是不同的,可以进行个人定制化设置.
“strict”: true, 进行类型检查,开启严格模式
“noImplicitAny”: true, 检查any类型
“strictNullChecks”: true, 检出null 和undefined
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
但是实际上,只用开启strict": true,就会自动检查其余两项
2.数据类型
基元类型
string number boolean
let str :string = "hello string";
let num : number = 123;
let boo : boolean = false;
数组类型
type[] Array
let arr: number[] = [1,2,3];
let arr2: Array<number> = [1,2,3];
第一种定义方法type可以是任何的基元类型.
第二种泛型的方式,传入一个类型,然后这个数组的元素类型就是统一的.
any类型
不希望某个特定的值导致类型错误检查.
let obj : any = {
x : 0
}
类型注释
函数返回值类型注释
函数参数为对象类型
function printCode(pt:{name:string;age:number}) : void{
console.log(pt.name)
console.log(pt.age)
}
printCode({
name:'zhangsan',
age:12
})
值得注意的是,参数是对象时,每个对象的属性使用分号隔开的,当然,逗号也是可以的.那么问题来了,可选参数怎么处理呢?
是可选参数的时候,在那个属性上加一个?就可以了
function printCode(pt:{name:string,age?:number}) : void{
console.log(pt.name)
console.log(pt.age)
}
printCode({
name:'zhangsan'
})
联合类型
let strs : number|string = "123";
function fun1(names: string | number){
console.log(typeof names)
}
fun1("zhangsan");
fun1(1232344);
类型别名
有点像自定义类型
就是给类型起别名.
用type 关键字
type Point = {
x : number,
y : number
}
function printCode(pt: Point){
console.log(pt.x+pt.y)
}
type Id = number | string
function ids (id: Id){
console.log('====================================');
console.log(id);
console.log('====================================');
}
printCode({x:1,y:3});
ids(45)
起别名的扩展:相当于继承:
type Person = {
name: string,
age: number
}
// 相当于继承了
type Student = Person & {
honey: boolean
}
// 实例化
let student : Student = {
name: 'zhangsan',
age: 12,
honey: true
}
console.log(student)
接口
用关键字interface来定义接口
interface Point{
x: number,
y: string
}
function fun3(pt: Point){
console.log(pt.x)
}
fun3({
x: 3,
y: 'string'
})
接口的扩展:相当于继承
interface Person{
name: string,
age: number
}
// 相当于继承
interface Student extends Person{
honey: boolean
}
// 实例化
let student : Student = {
name: 'zhangsan',
age: 12,
honey: true
}
console.log(student)
在interface中可以同名听译类型,而type不可以,同名的类型会将属性合并.
interface Person {
name: string,
}
interface Person{
age: number
}
let person: Person = {
name: 'zhansan',
age: 12
}
console.log(person);
type和interface的区别
- type不支持重复定义,而interface支持,可以通过同名来扩展字段
- type的扩展方式是用& type Student: Person & {},而interface是用关键字extends
- type的定义是赋值式,type Student = {},而interface 是 interface Person{}
类型断言
断言相当于强转就是把一种数据类型转化为可能的另一种数据类型
let str = <string>"1234";
let str1 = "1234" as string
cons name =( "1234" as unknown) as string
文字类型
文字类型就相当于是一个常量,定义了就只能传递这个值,不可以改变,就相当于是const当以的常量..
如果函数参数类型是文字类型’hello’,就意味着,函数的参数只能是’hello’
const hello = "helloworld"
// hello = "ee"
// 定义文字类型,那这个x的值就只能是hello
let x: 'hello' = "hello";
console.log(x);
// 如果参数类型是文字类型'hello',就意味着,函数的参数只能是'hello'
function fun(s: 'hello'){
console.log(x)
}
fun('hello')
数字的文字类型使用是一样的
function fun(a: 1){
console.log(a);
}
// 这里就只能传入1
fun(1)
null和undefined
let x: null = null;
let y: undefined = undefined;
枚举
通过enum关键字来定义
enum Dir{
Upo = 1,
down,
left,
right
}
// 设置了第一个,后面的数据会一次增加
console.log(Dir.Upo); // 1
console.log(Dir.down);// 2
不太常用的原语
// 将target:es2020
const onHand : bigint = BigInt(1000)
const an:bigint = 100n
console.log(onHand,an);
const a = Symbol("name")
const b = Symbol("name")
console.log(a===b); //false
3.类型缩小
当一个变量的类型是一个联合类型的时候,使用可能会出错,这个时候就需要将类型的范围变小.怎么将范围变小呢,通过typeof还进行类型守卫.
function pri(strs: string | string[] | null){
if(typeof strs ==='string'){
// todo
}else if(typeof strs === 'object'){
// todo
}else{
//todo
}
}
通过类型的判断来对参数进行相应的处理
真值缩小
条件,&&,||,if语句,布尔否定
就是需要判断一个值不是 null undefined 0n 0 ’ ’ 等
function pri(strs: string | string[] | null){
if(typeof strs ==='string'){
console.log(strs);
}else if(strs && typeof strs === 'object'){
for(let s of strs){
console.log(s);
}
}else{
console.log(strs);
}
}
就是通过一些运算来排除参数的值为空的情况.
function fun(values: number|null){
if(!values){
console.log("参数为空");
}else{
console.log(values*100);
}
}
等值缩小
1.判断一个参数不等于null,就会自动判断也不等于undefined,利用!= 或==来判断
function fun(str: null|undefined|string){
if(str != null){
console.log(str)
}
}
fun("333") // 333
fun(null) // 没有打印
fun(undefined) //没有打印
2.如果判断两个参数==,他会自动去找这两个参数的类型一样,如果一样才判断
function fun(a:string|number,b:string|null){
if(a==b){
console.log("==")
}else{
console.log(a);
console.log(b);
}
}
in操作符
判断一个参数是否具有某一个方法或参数,如果所有那这个参数就是这个方法所属的类型.
type Fish = {swin:()=>{}}
type human = {swin?:()=>{}}
type bird = {sky: ()=>{},sss:()=>{}}
function fun(anim:Fish|human|bird){
// 如果 anim有sky方法,就可以判断,它可能是bird类型
if("sky" in anim){
anim.sss()
}else{
(anim as Fish).swin()
}
}
instancesof
x instancesof Foo 判断x是不是一个类的实例
分配缩小
就比如一个三目运算符,这个时候的x,系统就会自动根据两边的值来给x赋上数据类型,在这里x的类型就是 number|string,
如果你再想给x赋值成true就会报错.
控制流分析
就是通过if判断加上typeof的判断来控制变量的类型
never类型与穷尽性检查
表示一种不存在的状态.
never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环),示例代码如下:
let x: never;
let y: number;
// 运行错误,数字类型不能转为 never 类型
x = 123;
// 运行正确,never 类型可以赋值给 never类型
x = (()=>{ throw new Error('exception')})();
// 运行正确,never 类型可以赋值给 数字类型
y = (()=>{ throw new Error('exception')})();
// 返回值为 never 的函数可以是抛出异常的情况
function error(message: string): never {
throw new Error(message);
}
// 返回值为 never 的函数可以是无法被执行到的终止点的情况
function loop(): never {
while (true) {}
}
4.函数
函数类型表达式
function a(fn:(a:string) =>void){
fn("hello")
}
function b(s:string){
console.log(s);
}
gener(b)
函数a的参数传入的是一个函数类类型,fn,函数类型怎么定义的呢? fn:(a:string) => void 这个函数传入个string类型的数据,返回值为void,其中b函数,就是这个函数类型的具体实现
为了直观的表达.改为下面的方式,
type func = (a:string) => void
function a(fn:func){
console.log("hello")
}
function b(s:string){
console.log(s);
}
a(b)
调用签名
type DescFunc = {
// 函数的属性
desc : string,
// 函数的定义
(str:string):string
}
// 创建一个函数,将构造的这函数类型传入
function todos(fn: DescFunc){
// 调用属性
console.log(fn.desc);
// 函数可以直接调用,实际上DescFunc就式自己定义的函数
// 调用函数
fn('hello')
}
// 实现这个具体的函数类型DescFunc
function f1(s:string){
return s;
}
f1.desc = "hello";
// 调用函数,传入参数f1
todos(f1);
构造签名
Ctor是一个类
泛型函数
function fu<T>(arr: T[]): T | undefined{
return arr[0]
}
fu<number>([1,2,3,4])
fu(['1','2'])
如果函数的返回值不确定,可以用泛型来解决.泛型就是随机应变.
限制条件
function fun <T extends {length:number}> (a:T,b:T){
if(a.length>b.length){
return a.length
}else{
return b.length
}
}
console.log( fun([1,2,3],[1,2,3,4,5,6]));
不能保证a和b没有length这个属性,让泛型T去继承length这个属性
指定泛型参数
就是给泛型指定类型.
编写优秀通用函数的准则
可选参数
用?选择
function fun(str?: number){
console.log(str);
}
fun()
永远不要在回调函数中写一个可选参数.
函数重载
前两个式重载签名
第三个式实现重载签名
function sum(a:number):Date;
function sum(b:number,c:number):Date;
function sum(a:number,b?:number,c?:number):Date{
return new Date();
}
编写好的重载
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zRNKCoJ3-1648267501861)(assets/1645860199637.png)]
函数内的this
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GvSGujA-1648267501862)(assets/1645860785339.png)]
其他类型
void object unknow never Function
参数的展开运算符
… 形参展开
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-reW3truM-1648267501864)(assets/1645861091853.png)]
将形参合并到一个参数中,在这个函数中.10对应到n,而剩余的参数自动合并到m中
实参展开
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2SBfdzaN-1648267501864)(assets/1645861358977.png)]
5.对象
interface Person{
name: string,
age: number
}
type Student ={
name: string,
age: number
}
function fun(p: Person){
console.log(p);
}
可选属性
就是给属性加上问号
type Student ={
name: string,
age?: number
}
function fun(p: Student){
console.log(p);
}
fun({name:"zhangsan",age:12})
fun({name:"zhangsan"})
只读属性
不会改变值加上readonly关键字
type Student ={
readonly name: string,
age?: number
}
function fun(p: Student){
console.log(p);
// 会报错
//p.name="h"
}
fun({name:"zhangsan",age:12})
如果把readonly加在类上面,这个类中的属性是可以改变的
type Student ={
readonly name: string,
age?: number,
readonly stu:{
as: string
}
}
function fun(p: Student){
console.log(p);
p.stu.as="hh"
}
索引签名
interface Student{
// 索引的名字不确定,单数知道索引的类型式number,然后索引的值为string
[index: number]: string
}
let yeStu: Student = ['q','b']
console.log(yeStu[0]);
就是用来规定类中的属性的类型和属性值的类型.
扩展类型
用extends来扩展就是继承
interface Person{
name: string,
age: number
}
// 相当于继承
interface Student extends Person{
honey: boolean
}
交叉类型
interface A{
name: string
}
interface B{
age:number
}
// 通过type 让AB具有A和B和属性
type AB = A & B;
let AB = {
name: 'zhangsan',
age:12
}
// 不同type也可以
function func(C: A & B){
//todo
}
定义交叉类型有两种,第一种是通过type和&来完成,第二种是作为函数的参数.
泛型对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TgVCaE5J-1648267501865)(assets/1645865205391.png)]
interface Person<T>{
name: T,
age:number
}
let person: Person<string>={
name: '张三',
age: 12
}
6.类型操纵
泛型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5uo2ih46-1648267501865)(assets/1645866061982.png)]
泛型类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y8TnOEDW-1648267501866)(assets/1645866592097.png)]
function fun<T> (ag:T) : T {
return ag;
}
let myFun: <T>(ag: T) => T = fun
interface Inter{
<T>(ag: T) : T
}
let MyFun1 : Inter = fun;
将泛型定义成一中数据类型
还有一种方式,这种方式更好.
interface Inter<T>{
(ag: T): T
}
let Myfun: Inter<string> = fun
泛型类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wzRsKXif-1648267501867)(assets/1645867099053.png)]
class Person<T>{
name: T,
add: (x: T,y: T) => T
}
let person = new Person<string>()
person.name = "zhangsan"
person.add =function ('a','b'){return "hello"}
泛型约束
就是用extends来约束,就是告诉开发者,在用这个类的时候,传入的泛型类型,必须带有一些类型
function fun<T extends string>(arg:T){
console.log(arg.length);
}
在约束中使用类型参数
keyof就是约束key一定要是Td的一个属性
// 两个参数,一个是类.一个是类的属性 keyof就是约束key一定要是Td的一个属性
function fun<T,key extends keyof T>(obj:T,key:key){
console.log(obj[key]);
}
let x = {
a:1,
b:2
}
fun(x,"a")
<T , key extends keyof T> key extends keyof T的以上就是key一定是T的一个属性
在泛型中使用类类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cmRv94du-1648267501868)(assets/1645867951207.png)]
keyof
type Person = {
name: string,
age: number
}
type P = keyof Person;
let p1 : P = "name";
let p2: P = "age";
let p3: P = "dd"; //报错合格
这个P就只包含name和age
typeof
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JDGuUqYm-1648267501869)(assets/1645871406285.png)]
判断一个变量的类型
索引类型
type Person={
name: string,
age: number
}
type Name = Person["name"]
let name1: Name = "zhangsan"
条件类型
三目运算
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OwbKcA3i-1648267501870)(assets/1645872363283.png)]
7.类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xIlkICJH-1648267501871)(assets/1645879746309.png)]
// 如果不加!会报没有初始化值的错误
class Person{
name!: string
age!: number
}
let person = new Person()
person.name = "zhangsan";
person.age = 10;
console.log(person);
或者用构造函数
class Student{
name
age
constructor(){
this.name='张三',
this.age = 10
}
}
console.log(new Student());
readonly
// readonly 可以在构造函数中被二次修改
class Person{
readonly name: string = "hello"
constructor(){
this.name = "world"
}
}
// 但是不可以在外面二次修改
构造器
1.构造函数不能有类型参数
2.构造函数不能有返回类型注释
class Person{
name: string
age: number
constructor(name: string,age: number) {
this.name = name
this.age = age
}
}
let p = new Person('zhangsan',12);
方法
除了有类型注释以外,和js方法没有什么区别
getter/setter
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wPkbJfyx-1648267501872)(assets/1645882576231.png)]
class C{
_length = 0
get length(){
return this._length
}
set length(value){
this._length = value
}
}
let c = new C()
c.length
c.length = 100
索引签名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1eUNXDXz-1648267501873)(assets/1645883184795.png)]
索引可以约束类中属性的定义规则
class Person{
[s: string]: string | (()=>boolean)
name = 'zhangsan'
check(){
return true;
}
}
implement实现接口
interface Person{
fun(): void
}
class Student implements Person{
fun() {
//todo
}
}
一个类可以实现多个接口
extends
和前面的一样
重写
重写发生在继承中,重写父类的方法.
class Person{
fun(){}
}
class Student implements Person{
// 重写父类的方法
fun(name?: string) {
}
}
初始化顺序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FXlLjZSe-1648267501874)(assets/1645885049801.png)]
继承内置类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G3kMljRg-1648267501875)(assets/1645925333815.png)]
成员可见性
public 默认是可见的
protected 在内部和子类访问
private 只能在内部访问
静态成员
用static修饰,可以直接用类名访问
类的静态区块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ozuWe5Yb-1648267501876)(assets/1645926612311.png)]
泛型类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IqOx4Bsu-1648267501876)(assets/1645927214624.png)]
this类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ntgUBqP-1648267501877)(assets/1645927830511.png)]
抽象类和成员
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZY5Med7o-1648267501878)(assets/1645928804564.png)]