当前位置:   article > 正文

TypeScript

TypeScript

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、接口的作用

点击查看参考csdn
接口可多继承(接口内有同样类型名,但类型不同,则不可继承),类不行

  1. 限制对象
  2. 限制数组
  3. 限制函数
  4. 类实现接口
  5. 接口继承接口
  6. 接口可继承类,类再实现接口
    在这里插入图片描述
class School{
    private b:string='ss'
}
//报错
// class Student  implements test1{
//     c=2
//     a=''
// }
//正常
class Student extends School implements test1{
    c=2
    a=''
}

interface test1 extends School{
    a:string
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

二、类型断言

点击查看参考csdn
语法格式:
(1) <类型>值
(2)值 as 类型

注意:
1. 类型断言更像是类型的选择,而不是类型的转换
2. 联合类型:我们只能访问此联合类型的所有类型里共有的成员。
  • 1
  • 2
  • 3
//这是错误的代码
//那么就是说,length应该是string和number共有的属性才对,
//但是number没有length的属性,所以上述代码放在ts文件里,
//if语句中的length就会报错(“number”上不存在属性“length”)
function func(val: string | number) :number {
    if (val.length) {
        return val.length
    } else {
        return val.toString().length
    }
}
//正确要先判断类型
function func(val: string | number) :number {
    if (typeof val == 'string' && val.length) {
        return val.length
    } else {
        return val.toString().length
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

interface a{
    b:string
}
interface b{
    c:string
}
interface c extends a,b{
    d:string
}
class e implements c{
    d=''
    b=''
    c=''
}
//使用类型断言可以初始化空,后面可以单独初始化
let f:c=<c>{}
f.b=' '
//会报错
let f:c={}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

三、type关键字

点击查看参考csdn

//type是用来定义新类型,常结合typeof使用
type FType = boolean | string | number;


type Shape = { name: string }
type Circle = Shape & { radius: number }
function foo(circle: Circle) {
  const name = circle.name
  const radius = circle.radius
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

四、 declare 关键字

点击查看参考csdn
类型声明的作用?

  1. 用来为已存在的 JS 库提供类型信息;声明文件可以让我们不需要将JS重构为TS,只需要加上声明文件就可以使用系统。
    添加链接描述
    定义.vue文件或模块
  2. 定义纯粹的类型

下面是对原有的js提供类型

declare let age: number;
declare function getAge(): number | string;
declare class Person { };
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述
下面是定义纯粹的类型

//纯粹定义类型,要结合type,declare 可有可无
declare type dd = {
    a:string
}

declare type sd = string
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果.d.ts文件过多或类型过多,可以使用module,

utilTypes.d.ts文件

declare module "cc"{
   export declare type dd = {
        a:string
    }
    
    export declare type sd = string
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

test.ts文件

import { dd } from "cc"
let aa:dd= {
    a:"11"
}
  • 1
  • 2
  • 3
  • 4

如果不使用module,可以直接使用,不用导入

如果.d.ts文件不在根目录下,需要在tsconfig.ts配置include

{
	"compilerOptions": {
	},
	"include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts"], // **Represents any directory, and * represents any file. Indicates that all files in the src directory will be compiled
	"exclude": ["node_modules", "dist"] // Indicates the file directory that does not need to be compiled
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

五、常用工具类

添加链接描述
重点记住下面几个

  1. Record
//Record:生成接口类型,然后我们使用传入的泛型参数分别作为接口类型的属性和值
//源码
type Record<K extends keyof any, T> = {
  [P in K]: T;
};
//使用
type MenuKey = 'home' | 'about' | 'more';
interface Menu {
  label: string;
  hidden?: boolean;
}
const menus: Record<MenuKey, Menu> = {
  about: { label: '关于' },
  home: { label: '主页' },
  more: { label: '更多', hidden: true },
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  1. 接口类型(对象)
    Pick
//可以从类型中选取出指定的键值,然后组成一个新的类型
//源码
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};
//使用
// 定义一个通用的 Person 类
interface Person {
  name: string;
  age?: number;
  weight?: number;
}

type NewPerson = Pick<Person, 'name' | 'age'>;

// 相当于
interface NewPerson {
  name: string;
  age?: number;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

Omit

//返回去除指定的键值之后返回的新类型
//源码
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

//使用
// 定义一个通用的 Person 类
interface Person {
  name: string;
  age?: number;
  weight?: number;
}

type NewPerson = Omit<Person, 'weight' | 'name'>;
// 相当于
interface NewPerson {
  age?: number;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

为接口或type增加新key

//一
type user ={
  name:string
  age:number
  sex:string
}
type newuser ={dqwd:number} & user

//二
//
type MyType {
  key: string;
  value: number;
}

// 新类型必须使用interface,type无法使用继承
interface NewMyType extends MyType {
  newKey: number;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

扩展:使用&不当可能会出现错误

type aa=string | number
type c=aa & string  //string




interface aa{
  a:number
  b:string
}
interface cc{
  a:string
}
//a属性编程never无法赋值,报错
let c:aa & cc={
  b:'',

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

接口修改key或keyi的类型
思路:新的key名字随意,直接修改不太好做到,可以先剔除需要修改的key在增加即可

type user ={
    name:string
    age:number
    sex:string
  }
 //写成通用函数有难度,下面的简单
type Sx =  Omit<user,"name"> &{"hahah":number}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

新的key名字包含原来修改的key名字

修改一个

//T是接口,K是修改的key,写死getkey
type ChangeOneKey<T extends {[p :string]:any},K extends keyof {[p :string]:any}> =  {
  [p in  keyof T as `get${keyof Pick<T,K>}` | keyof Omit<T,K>]: T[p]
} 
  • 1
  • 2
  • 3
  • 4
  1. Exclude
//从 T 中剔除可以赋值给 U 的类型,如果 T 是 U 的子类型,则返回 never 不是则返回 T
//源码
type Exclude<T, U> = T extends U ? never : T (会遍历T的每一个类型进行判断)

普通判断不会遍历,注意区分
```javascript
type A = number | string | boolean
type B = number | boolean
type ssss= A extends B ? never : A
//ssss:	number | string | boolean
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

//使用
type A = number | string | boolean
type B = number | boolean

type Foo = Exclude<A, B>

// 相当于
type Foo = string

	
或使用	extends

```javascript
type sadqwq = "1"|"2"|"333"
function pluck<T, K extends sadqwq>(a:T,b:K):void{
        console.log(b);  
  }
  pluck(2,"2")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

六、keyof和in

keyof和in
keyof
前言:类型不可以作为值传递,即不可以打印,想要查看可以先注解一个变量,鼠标放上去就可以看到类型

type Person = {
  id: number;
  name: string;
  age: number;
};

type P1 = keyof Person; //'id' | 'name' | 'age'

type P2 = Person[keyof Person];  // number | string
1. Person['key'] 是查询类型(Lookup Types), 可以获取到对应属性类型的类型;
2. Person[keyof Person]本质上是执行 Person['id' | 'name' | 'age']3. 由于联合类型具有分布式的特性,Person['id' | 'name' | 'age'] 变成了 Person['id'] | Person['name'] | Person['age']4. 最后得到的结果就是 number | string.


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

in看成forin循环,被 in 进行(遍历)运算的都是联合类型

type cc= { [P in 'x' | 'y']:P }//P进行了两次遍历,每次遍历P都不一样
//结果
type cc = {
    x: "x";
    y: "y";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

七、 & \

& | 都可以看做联合类型,&用于接口联合,| 可以用做普通类型

string | number
string & number //错误
type z= {a:string} & {b:string} //自定义类型z必须要有a b 两个属性

  • 1
  • 2
  • 3
  • 4

联合类型 |
当联合类型是类的联合时,One | Two 只能使用两个类中共同的方法

 class One{
            public up(){
                console.log("up");
                
            }
            public say(){
                console.log("One say");
                
            }

        }
        class Two{
            public down(){
                console.log("down");
                
            }
            public say(){
                console.log("Two say");
                
            }
        }
        let one=new One()
        let two = new Two()
        let three:One|Two=<One| Two>{}
        three['say']=one['say']    
         //three.say=one['say']  共有方法怎么定义都可以
        three["up"]=one['up'] 
        //three.up=one['up'] 会直接爆红,上面定义不会爆红,调用时才爆红   
        three.say()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

八、 extends

extends 较为复杂,不仅仅代表继承

extends 可用于条件类型
分配条件类型
条件类型

type c= string | number
type a=number
type b=string | number
type g= object
//左边小类型可以赋给右边大类型,取值第一个
type d= a extends c? never: ' '  //never
type e= b extends c? never: ' '	//never
type f= b extends c? never: ' '	//never
type h= g extends c? never:''	//''
//注意是接口类型或对象类型时,只有相同时,左边才能赋值给右边
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

九、 对象动态添加属性

添加链接描述
ts不允许对象动态

let studet={
    a:2
}
studet.cc=3   //报错
studet['cc']=3  //虽然不报错,但访问还是会报错,不存在改属性
log(studet.cc)//不存在改属性


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以加一个接口,实现自定义增加属性

interface studet{
    [key:string]:number
}
let studet:studet={
    a:2
}
studet.cc=3    //不会报错
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

十、方法的重载和重写

添加链接描述
添加链接描述
1.重写方法名和参数(包括类型)不能改变,
2.重载方法名相同,参数必须不同(可以仅仅类型不同)注意:必须要把精确的定义放在前面,最后函数实现时,需要使用 |操作符或者?操作符,把所有可能的输入类型全部包含进去,以具体实现。 即最下面的方法需要兼容上面的方法

//重载
function run(num:number):void;
function run(str:string,flag:boolean):void;
function run(str:string,flag?:boolean):void;
function run(str:number|string,flag?:boolean):void{
    if(typeof str === 'string'){
        console.log("fur")
    }else{
        console.log(1)
    }
}
run(1)
run("fur")
run("fur",true);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

十一、装饰器的作用

添加链接描述
结论:类装饰和属性装饰器同是在运行时调用,方法装饰器是在方法调用时调用

类装饰
例如声明一个函数 addAge 去给 Class 的属性 age 添加年龄.

function addAge(constructor: Function) { 
  constructor.prototype.age = 18; 
} 
 
@addAge 
class Person{ 
  name: string; 
  age!: number; 
  constructor() { 
    this.name = 'huihui'; 
  } 
} 
 
let person = new Person(); 

console.log(person.age); // 18 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

方法装饰器参考

方法装饰:类似Object.defineProperty(几乎一样),在方法调用时调用(方法调用之前)。
接受三个参数
target :
静态成员 :类的构造函数
实例成员 :类的原型对象
method : 成员的名字
descriptor : 成员的属性描述符

应用:函数调用日志
class Techer extends Proper{
    constructor(){
        super()
    }
    @log
    a(c:number|string):string{
        console.log("aaa");
        return '1111'
    }
}
function log(target:Object, name:string, descriptor:any) {
    var oldValue = descriptor.value;
    console.log(" descriptor.value", descriptor.value);
    
    descriptor.value = function () {
        //arguments是name函数的参数
        console.log(`Calling "${name}" with`, arguments);
        //注意此时修改了原函数this指向,实例调用带有此注解的方法,this指向null
         oldValue.apply(null, arguments);
    }
    // return descriptor;
}
let techer=new Techer()
techer.a('c')    //调用见图
techer.a('d')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

在这里插入图片描述
装饰器工厂需要调用并返回一个装饰器

执行顺序
当多个装饰器应用于一个声明上,将由上至下依次对装饰器表达式求值,求值的结果会被当作函数,由下至上依次调用,例如如下:

function f() { 
    console.log("f(): evaluated"); 
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) { 
        console.log("f(): called"); 
    } 
} 
 
function g() { 
    console.log("g(): evaluated"); 
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) { 
        console.log("g(): called"); 
    } 
} 
 
class C { 
    @f() 
    @g() 
    method() {} 
} 
 
// 输出 
f(): evaluated 
g(): evaluated 
g(): called 
f(): called 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

十二、类

类可以作为类型,(包括继承父类)
如果类有私有属性或私有方法,则只能用来限定该类的实例

只读属性

class Mytest{
    readonly a:number=2
}
  • 1
  • 2
  • 3
  • 4
  • 5

十三、抽象类

抽象类继承抽象类,子抽象类可以实现父类抽象方法也可以不实现(实现没啥用),但具体类必须实现
在这里插入图片描述
抽象类和类可访问性都是父级大于等于子集

十四、命名空间

注意:编译后的js都要引入
添加链接描述

十五、泛型

添加链接描述
在这里插入图片描述

//官网例子
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
  return names.map(n => o[n]);
}

interface Person {
    name: string;
    age: number;
}
let person: Person = {
    name: 'Jarid',
    age: 35
};
let strings: string[] = pluck(person, ['name']); // ok, string[]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
function pluck<T, K extends keyof T>(o: T, names: K[]): T[] {
    // return names.map(n => o[n]);
    //会报错,数组里的类型不能写死
    return [{name:'11',age:1}]
  }
  
  interface Person {
      name: string;
      age: number;
  }
  let person: Person = {
      name: 'Jarid',
      age: 35
  };
  let strings = pluck(person, ['name']); // ok, string[]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

十六、never

nver类型不可以被赋值

//初始化数组时,没有定义每一项的类型,则被初始化成never类型,后面无法赋值
const bann = []
bann[1] = 2  //不能将类型“number”分配给类型“never”。
  • 1
  • 2
  • 3

never用于对象(接口)等的属性(属性非属性值,例如:{a:1} 即a使never)时,属性被删除

添加链接描述

type VariantA = {
    a: string,
}

type VariantB = {
    b: number,
}

declare function fn(arg: VariantA | VariantB): void


const input = {a: 'foo', b: 123 }
fn(input) // 这违背了我们的设计,但是 TypeScript 不会报警

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
type VariantA = {
    a: string
    b?: never
}

type VariantB = {
    b: number
    a?: never
}

declare function fn(arg: VariantA | VariantB): void


const input = {a: 'foo', b: 123 }
fn(input) // ❌ Types of property 'a' are incompatible

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

十七、接口限制对象

//无限个属性

interface objectInter{
     //会报错
    // name:string
    [key:string]:number
}
let myobj:objectInter={
    a:1,
    b:2
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

//有限属性

interface Person {
  name: string;
  age: number;
}

type Optional<T> = { 
  [K in keyof T]?: T[K] 
};

const person: Optional<Person> = {
  name: "Tobias"
};

//  in  它的语法与索引签名的语法类型,内部使用了 for .. in。 具有三个部分
type Nullable<T> = { [P in keyof T]: T[P] | null }
type Partial<T> = { [P in keyof T]?: T[P] }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

十八、映射和重映射

映射:in 与 联合类型连用
视频
笔记
as 对映射类型中的键进行重新映射

十九、&实现过滤

type aa=string | number
type c=aa & string  //string




interface aa{
  a:number
  b:string
}
interface cc{
  a:string
}
//a属性编程never无法赋值,报错
let c:aa & cc={
  b:'',

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

二十、promise泛型

Promise:Promise的泛型T代表promise变成成功态之后resolve的值,resolve(value)
添加链接描述

二十一、函数

泛型函数

type sayType = <T>(operate: T, person: string, content: string) => boolean;
var say: sayType = function (operate, person, content) { 
    if (person === '' || content === '') return false;
    console.log(`${person} ${operate}:${content}`);
    return true;
};
say<string>('','','')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

添加链接描述

const foo = <T>(x: T): T => x;

const foo = <T extends {}>(x: T): T => x;

const foo = <T extends Record<string, unknown>>(x: T): T => x;
//<T>(x: T) => T类型       x => x函数
const foo: <T>(x: T) => T = x => x;

const identity = <T>(arg: T): T => {
    console.log(arg);
    return arg;
};

const renderAuthorize = <T>(Authorized: T): ((currentAuthority: CurrentAuthorityType) => T) => (
    currentAuthority: CurrentAuthorityType,
  ): T => {
     return
 };

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

函数表达式

ts中的 =>用来表达函数的定义: 左边是输入类型,需要用括号括起来,右边是输出类型
let kate3: (x: number, y: number) => number = function (x: number, y: number): number {
  return x + y;
}
// ts中的 =>用来表达函数的定义: 左边是输入类型,需要用括号括起来,右边是输出类型

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

函数声明

function sayHi3(x:number,y:number): number {
  return x + y
}

sayHi3(1,5)
// sayHi3(2,5,7) //Expected 2 arguments, but got 3.
// sayHi3(5) // An argument for 'y' was not provided.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

接口限制函数

interface SayHi4 {
  (x: number, y: number): number;
}
let sayhi6: SayHi4 = function(x, y) { return x+y}

泛型接口
interface Search {
  <T,Y>(name:T,age:Y):T
}

let fn:Search = function (name id){
  console.log(name, id)
  return name;
}
fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

剩余参数

可以使用 ...rest 的方式获取函数中的剩余参数(rest 参数)
function push(array: any[], ...items:any []) {
  items.forEach(item => {
    array.push(item)
  })
}

let a: any[] = []
push(a, 1,2,3,4)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

二十二、接口中使用泛型

// 注意,这里写法是定义的方法哦
interface Search {
  <T,Y>(name:T,age:Y):T
}

let fn:Search = function <T, Y>(name: T, id:Y):T {
  console.log(name, id)
  return name;
}
fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型

//写法定义的是属性
interface objType {
  money: (value: number) => number
  arr: () => string[]
}
const obj2: objType = {
  money: (val) => val,
  arr: () => ['1'],
}
 
console.log(obj2.money(2))
console.log(obj2.arr())

//接口使用泛型
interface objType<T1, T2> {
  money: (value: T1) => T1
  arr: () => T2[]
}
const obj2: objType<number, string> = {
  money: (val) => val,
  arr: () => ['1'],
}
 
console.log(obj2.money(2))
console.log(obj2.arr())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

添加链接描述

二十三、infer

添加链接描述
添加链接描述

infer语法的限制如下:
infer只能在条件类型的 extends 子句中使用
infer得到的类型只能在true语句中使用, 即X中使用

/**
 * Obtain the return type of a function type
 */
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;


type Last<Arr extends unknown[]> = Arr extends [...infer rest,infer Ele]? Ele : never; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

二十四、typeof

添加链接描述
typeof作用:
1、可以拿到某个js文件类型

import XtxSwiper from './XtxSwiper.vue’
type xx = typeof XtxSwiper 
  • 1
  • 2

2、可以拿到某个变量类型

typeof和数组使用
const arr12=[1,2,'s']
//type lei1 = (string | number)[]
type lei1= typeof arr12

typeof和数组使用
const arr123=[1,2,'s'] as const
//type lei2 = readonly [1, 2, "s"]
type lei2= typeof arr123

typeof和函数使用
function add(a: number, b: number) {
  return a + b;
}
// (a: number, b: number) => number 
type AddType = typeof add; 

typeof和对象使用
const lolo = {
  name: "lolo",
  age: 7,
  address: {
    province: "福建",
    city: "厦门",
  },
};
 
interface Person {
  name: string;
  age: number;
  address: {
    province: string;
    city: string;
  };
}

//type Person = {
//    name: string;
//    age: number;
//    address: {
//        province: string;
//        city: string;
//    };
//}
type Person = typeof lolo;

// type Address = {
//     province: string;
//     city: string;
// }
type Address = typeof lolo["address"];
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

二十五、as const

添加链接描述

不加as const
const arr123=[1,2,'s']
//(number | string) [1, 2, "s"]
type sadas=typeof arr123

加as const
const arr123=[1,2,'s'] as const
//readonly [1, 2, "s"]
type sadas=typeof arr123

不加as const
let aaa:string='sdad' 
//string
type asdqda=typeof aaa

加as const
let aaa:string='sdad'  as const
//'sdad'
type asdqda=typeof aaa
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

二十六、数组

添加链接描述

二十七、获取数组或对象的索引签名

数组的索引只能是number

数组
type asweq=(number|string)[]
// string | number   
type dsad=asweq[number]

// 1 | 2
type cds = [1,2][number] 

接口
  interface AnyObject {
        [key: string]: number
      }
    //number
    type dasdqwe=AnyObject[string]


    interface P{
        a:string
        b:number
    }
	//报错
    type dasdqwe2131=P[string]


//1
type cdssad={
    a:1
}['a']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

二十八、元组

    type tesla = ['tesla', 'model 3', 'model X', 'model Y'] 
    let ccsda:tesla=['tesla', 'model 3', 'model X', 'model Y']
    ccsda.push('model Y')
    ccsda.push('model 3')
    //报错,元祖里面没有number类型
     ccsda.push(3)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

二十九、协变和逆变

添加链接描述
逆变和协变都是型变,是针对父子类型而言的,非父子类型自然就不会型变,也就是不变
像 java 里面的类型都是通过 extends 继承的,如果 A extends B,那 A 就是 B 的子类型。这种叫做名义类型系统(nominal type)。而 ts 里不看这个,只要结构上是一致的,那么就可以确定父子关系,这种叫做结构类型系统(structual type)。
协变和逆变都是指可以成功的

协变:子可以赋值给父
逆变:函数才能实现(非官方,个人理解)
但是在 ts2.x 之前,也就是父类型可以赋值给子类型,子类型可以赋值给父类型,既逆变又协变,叫做“双向协变”

// 协变
  interface Person {
        name: string;
        age: number;
    } 
    
    interface Son {
        name: string;
        age: number;
        hobbies: string[]
    }

    let peo:Person={
        name:'',
        age:1,
    }

    let son:Son={
        name: '',
        age: 2,
        hobbies: ['']
    }
	//协变
    peo=son
	//报错
	 son=peo
//函数可以实现逆变
看链接

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

三十、x extends y? a:b

添加链接描述

  type A1 = 'x' extends 'x' ? string : number; // string
  type A2 = 'x' | 'y' extends 'x' ? string : number; // number
  
  type P<T> = T extends 'x' ? string : number;
  type A3 = P<'x' | 'y'> // ?
  • 1
  • 2
  • 3
  • 4
  • 5

分配条件类型:
意思就是对于使用extends关键字的条件类型(即上面的三元表达式类型),如果extends前面的参数是一个泛型类型,当传入该参数的是联合类型,则使用分配律计算最终的结果。分配律是指,将联合类型的联合项拆成单项,分别代入条件类型,然后将每个单项代入得到的结果再联合起来,得到最终的判断结果。

  • 防止条件判断中的分配
  type P<T> = [T] extends ['x'] ? string : number;
  type A1 = P<'x' | 'y'> // number
  //层级  unknown 是顶层,never是最底层,any是墙头草
  type A2 = P<never> // string
  • 1
  • 2
  • 3
  • 4

三十一、type

type:

  1. 起类型别名
    2.以原有类型的具体值(‘ss’,1 , true , {a:1})增加新类型
type aa= 1
let c:aa=1
//报错
// aa=2

type z={
    a:1
}
let zz:z={
    a:1,
    //报错
    // b:2
}

type xx=true
let flage:xx=true
//报错
// flage=false

//可以使用扩展运算符,但不能使用运算符,类型不能运算
type arr1=unknown[]
type arr2=unknown[]
type Concat<T extends arr1,U extends arr2>=[...T,...U]
//[1, 2]
type xs=Concat<[1],[2]>

//type限制函数,
type typ2={
  option<T>(c:T,d:number):number
  option1:<T>(a:T)=>string
}


type typ1={
  option(c:string):number
  option1:<T>(a:T)=>string
}
//参数可加可不加,如果加必须符合类型
let casdzx:typ1={
  option:()=>1,
  option1:()=>""
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

三十二、import type 和 import

import type 是 TypeScript 2.9 版本引入的一种新的类型导入语法。虽然在某些情况下 import 和 import type 可以互换使用,但它们并不完全等价。具体来说,import type 只能用于导入类型,而 import 则可以用于导入任何类型的值(变量、函数、类等)。

如果你使用 import 导入一个模块中的变量、函数或类,那么这些值会被加载到当前文件的命名空间中,可以随时使用它们。而如果你使用 import type 导入一个模块中的类型,则仅在编译阶段使用该类型,并且不会在运行时加载任何额外的代码。

通常情况下,建议尽可能使用 import type 来导入类型,因为它可以帮助减小生成的 JavaScript 文件的大小,并且更加明确地表达你的意图。但是如果你需要同时导入类型和值,或者需要动态导入模块,那么就必须使用 import。

三十三、声明合并

注意是接口声明合并,declare type 不能合并

例如合并接口sdd

untils.d.ts文件

  declare module "helo"{
    export interface sdd  {
     a:string,
     b:string,
     c:1
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

tee.d.ts文件

import * as untils from "helo"
declare module 'helo'{
    export interface sdd {
        c:number
       }
       export declare type ss= {
            e:number
       }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

利用接口合并可以对npm包进行扩展

/* eslint-disable */
import * as axios from 'axios';

// 扩展 axios 数据返回类型,可自行扩展
declare module 'axios' {
	export interface AxiosResponse<T = any> {
		code: number;
		data: T;
		message: string;
		type?: string;
		[key: string]: T;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

还可以对原对基本类型进行扩展,例如string(文件只要有一个export或import就是模块话文件)

这样可以骗过编译器,但是编译后的js无法运行

interface String{
    'b':()=>void;
}
let a = "a"
a.b= ()=>{
    console.log(1111);
}
a.b()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

三十四、InstanceType

添加链接描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/579611
推荐阅读
相关标签
  

闽ICP备14008679号