ts学习

56 阅读11分钟

安装

 npm install typescript -D

tsc终端命令说明

tsc ts文件名 			// 将ts文件编译成js文件
tsc ts文件名 -W 			// 监视ts文件,当ts文件发生改变的时候,自动编译成js文件
tsc				// 将根据tsconfig.json文件的配置内容对源文件进行编译

tsconfig.json文件说明

官方配置说明

tsconfig.json是ts编译器的配置文件,tsc命令将根据他的信息来对代码进行编译

{
  "inclde":[                 // 用来指定哪些文件需要被ts编译
     "./src/**/*"            // **表示任意目录 *表示任意文件
  ],
  "exclude":[                // 用来指定哪些文件不需要被编译,默认值是["node_modules","bower_components","jspm_packages"]
     ""
  ],
  "extends":"./configs/base", // 基础其他ts配置文件,类似导入吧
  "files":[                  // 指定需要编译的ts文件
    "core.ts"      
  ],
  "compilerOptions":{        // 指定ts文件编译的结果
    "target":"es2015",        // 指定ts文件编译的js版本为es2015(传递错误的值可以获取参考值)
    "module":"es2015" ,       // 指定ts文件的模块化为es2015(如果ts文件含有模块化的代码就需要进行此配置)
    "outDir":"./dist",         // 用来指定编译后文件的所在目录
    "outFile":"./dist/app.js", // 所有全局作用域的代码会合并到同一个文件中
    "allowJs":false,           // 是否编译js文件 默认为false
    "checkJs":true,            // 检测js代码是否符合语法,默认为false
    "removeComments":false,    // 是否移除注释
    "noEmit":false,            // 是否不生成编译后的文件
    "noEmitOnError":true,      // 是否当有错误时不生成编译后的文件
    "alwaysStrict":false,      // 是否使用严格模式
    "noImplicitAny":false,     // 是否不允许使用隐式使用any类型
    "noImplicitThis":false,    // 是否不允许使用没有明确类型的this
    "strictNullChecks":false,  // 是否检查对象可能为null 
    "strict":true,             // 是否所有的严格检查
    "baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"]       // 设置别名,注意别名设置后,如果只是单纯用tsc指令编译,不会对编译后的文件路径作出修改,需要用插件。
    },
  },
  "lib":[                    // 指定ts文件需要用到的代码提示库,默认包含前端所有用的库例如dom。如果配置了则会覆盖默认值,一般前端项目不需要配置,服务器项目才需要配置
   "dom"
  ],

}

@types/包名 | 第三方声明包的处理

背景:

当我们用 npm 等包管理工具安装第三方包的时候,有些包并不是 TypeScript 编写的,自然也不会导出 TypeScript 声明文件。 这种情况下,如果我们在 TypeScript 项目中引入了这种包,则会编译报错(没有设置 allowJS)。

作用:

安装第三方包的声明文件,能够在ts项目里面使用这些第三方包

工作流程:

比如如下代码:
const user: User = { name: "lucifer" };

Typescript 则会先在本模块查找 User 的定义。 如果找到,则直接返回。 如果找不到, 则会到全局作用域找,而这个全局默认就是指的就是 @types 下的所有类型定义。(注意目录页是可以配的)

常见的@types/包

@types/node

node环境需要,比如require。

类型声明

联合类型 | &

| 符号

let code : "a" | "b"; 			// code的赋值只能是a 或者 b
let code : boolean | string 		// code的赋值只能是boolean或者string类型  

& 符号

let code : {name:string} & {age:number};
code = {
    name:'xhp',
    age :29
}

任意类型 any unkonw

let code : any;				
let code : unknow;

他们的区别就是:
定义了any的code,可以接受或赋予所有的变量类型。
定义了unkonw的code,可以接受所有的变量类型,但是只能赋予类型为unkonw或者any的变量

例如:
let code1 : any;				
let code2 : unknown;
let code3 :string;
code1 = 'asd';
code2 = 'asd';
code3 = code1; 			// 不会报错
code3 = code2; 			// 报错,只能赋予赋予类型为unkonw或者any的变量

解决方法:使用类型断言
code3 = code2 as string; 	
code3 = <string>e;

void类型

函数执行后返回结果的类型

function f1():void{}

never类型

函数执行后返回错误结果的类型

function f1():never{
 throw new Error("报错咯")
}

object类型

对象结构的类型声明

let obj : {name:string}; 			// 指定obj的赋值结构必须只含有name 
obj = {name:'xhp'};

let obj : {name:string, age ?: number}; 	// 指定obj的赋值结构必须含有name age是可选的
obj = {name:'xhp',age:12};

let obj : {name:string, [keyName:string]:any};	// 指定obj的赋值结构必须含有name,其它随意。
obj = {name:'xhp',age:12,age1:'aa'};

fn类型

函数结构的类型声明

let f1 :(a:number, b:number) => number;
f1 = function(a:number, b:number) : number {
  return 10
}

数组类型

let array : string[];
let array : Array<string>;

元组类型

它的意思是有固定长度的数组。 let array : [string,string]; // 数组长度为2

枚举类型

指定变量只能从枚举类型里面获取值

enum Gender {
   Male = 0,
   Female = 1
}
let val : Gender;
val = Gender.Male;

class类型

class Person {
    name:string = 'xhp';		// 实例属性(通过新建的对象访问)
    static age:number = 18;     	// 静态属性(类属性,通过类访问)
    readonly height:number = 167; 	// 实例只读属性
    
    sayHello(){}                	// 实例方法
    static sayHi(){}            	// 静态方法

    year:number;

    construcotr(year:number){		// 构造函数
      this.year = year;
    }
}

抽象类abstract class

abstract class Department {

    constructor(public name: string) {
    }

    printName(): void {
        console.log('Department name: ' + this.name);
    }

    abstract printMeeting(): void; // 必须在派生类中实现
}

class AccountingDepartment extends Department {

    constructor() {
        super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
    }

    printMeeting(): void {
        console.log('The Accounting Department meets each Monday at 10am.');
    }

    generateReports(): void {
        console.log('Generating accounting reports...');
    }
}

type类型

类型的别名

type newString = 1 | 2 | 3 | 4 ;
let k : newString 
// 等价于
let k :  1 | 2 | 3 | 4 ;

type hellowType = {
     name:string
}
let k : hellowType = { name : 'xhp'}

type Fn = (x:number) => number
const fn:Fn = (x:number) => {
    return x
}

interface接口类型

对象类型接口

限制引用数据类型的结构

// 定义对象接口类型
interface Obj  {
     name:string;
     [x:string]:any;
}
let obj : Obj = { name : 'xhp', xxx:1}

// 定义数组接口类型
interface ArrayStr  {
     [x:number]:string;
}
let array : ArrayStr = ['1']

函数类型接口

interface Fn {
    (x: number, y: number): number
}
let fn: Fn = (a,b) => a+b

type、interface区别

  1. type 声明需要带 = 号,interface 不需要。
  2. type 不可以重复声明。interface可以,interface重复声明不是覆盖,而是合并。
  3. type能用来修饰普通数据类型和引用数据类型,interface只能修饰引用数据类型
  4. type函数与interface函数的格式是不一样的。
interface Fn { 
    (x: number, y: number): number
} 
type Fn = (x: number, y: number) => number

< T >泛型

不预先确定数据类型,具体的类型在使用的时候才能确定。

普通泛型

function log<T>(value:T):T {
    return value
}
log<string>('1')
log<number>(1)
log<number[]>([1])

接口泛型

interface Fn<T> {
    (x:T) : T
}
const fn:Fn<number> = function (x:number):number {
    console.log(x)
    return x
}
// 使用默认
interface Log<T = string>{
    (value:T):T
} 
let mylog:Log = (value:T):T {
    return value
}
mylog('1')

type泛型

type Fn<T> = (x:T) => T
const fn:Fn<number> = (x:number) => {
    return x
}

类型兼容性

接口兼容性,右边的属性大于左边的属性

interface Left {
    a:number,
    b:number,
}
interface Right {
    a:number,
    b:number,
    c:number,
}
let left:Left = {
    a: 0,
    b: 0
}
let right:Right = {
    a: 0,
    b: 0,
    c: 0
}
left = right

函数兼容性,右边的属性要小于左边的属性

let leftFn = function (a: number) { }
let rightFn = function (a: number,b:number) { };
rightFn = leftFn;   

&交叉类型

合并多个接口类型。

注意,如果不同接口但是多个key相同,如果key的类型不一致,使用会报错。

interface A {
    a:number
}
interface B {
    b:number
}
interface C {
    a:string
}
const abc : A & B = {
    a:1,
    b:2,
}

// 报错
const abc1 : A & B & C = {
    a:1,
    b:2,
}

|联合类型

限制变量类型要么a,要么b。

// 限制变量的数据类型
let a: number | string = 1

// 限制变量值的范围
let b: 1 | 2 | 3 | 4;
b = 1

interface D {
    a:number,
    b:number
}
interface E {
    c:number
    d:number
}

const xx: D | E = {
    c: 1,
    d: 1,
}
console.log(xx)

// 可区分的联合类型
interface A {
    a: number,
    c: number,
    name: 'A'
}
interface B {
    b: number,
    c: number,
    name: 'B'
}
function test(ab: A | B) {
    switch (ab.name) {
        case 'A':
            ab.a
            break;
        case 'B':
            ab.b
            break;
    }
}

extends的作用

1、接口继承

interface Shape {
    color: string;
}

interface Circle extends Shape {
    radius: number;
}

const myCircle: Circle = {
    color: "red",
    radius: 5
};

2、泛型约束

限制它必须是某种类型的子类型。

type A<T> = T extends string ? number : boolean 
// 如果T是string(也就是T是string的子类型),那么就是number类型,否则就是boolean类型 
type A1 = A<string> // A1 = number
type A2 = A<string | number> // A2 = boolean

TS内部自定义的api

1、keyof

取interface所有的key为联合类型

interface KeyOfData {
    a: string;
    b: number;
}
type KeyOfData1 = keyof KeyOfData
const t1:KeyOfData1 = 'a'

/**********原生实现*************/

type KeyOfData2 = 'a' | 'b'
const t2:KeyOfData2 = 'a'

2、Readonly

将interface所有的key设置为只读类型


interface ReadOnlyData1  {
    a: string;
    b: number;
}
type ReadOnlyData2 = Readonly<ReadOnlyData1> // { readonly  a: string;  readonly b: string; }

/********************原生实现***************************/
type MyReadonly<T> = { 
    readonly [P in keyof T]: T[P]; 
}
// 说明
// [P in keyof T] 等价于 [P in a | b] 等价于 a、b
// T[P] 等价于 ReadOnlyData1[a] 、 ReadOnlyData1[b] 等价于 string、 number
// 最后为 a:string、b:number

// 需要掌握的关键知识 [P in keyof T]的使用
type MyReadonlyTest1 = {
    [P in 'a' | 'b'] : string;
}
const d:MyReadonlyTest1 = {
    a: "",
    b: "",
}

3、Partial

设置接口的所有属性为可写或不可写

interface PartialData1  {
    a: string;
    b: number;
}
type PartialData2 = Partial<PartialData1> // { a?: string | undefined;   b?: string | undefined; }

/********************原生实现***************************/

type MyPartial<T> = { 
    [P in keyof T]?: T[P] | undefined; 
}
type PartialData3 = MyPartial<PartialData1>

4、Pick

设置只获取接口的部分属性

interface PickData1  {
    a: string;
    b: number;
    c: undefined;
}
type PicklData2 = Pick<PickData1, 'a' | 'b'> // { a:string, b:number }

/********************原生实现***************************/

type MyPick<T, K extends keyof T> = {  
    [P in K]: T[P]; 
}
// 说明
// K extends keyof T 表示 k只能是T的key的子集,也就是说 K 等于 a 或者 a|b 再或者 a|b|c 
// 故此在上面的例子中 [p in k] === [p in 'a' | 'b']
type PicklData3 = MyPick<PickData1, 'a' | 'b'>

5、Record

限制对象的keys类型为RecordData1

interface RecordData1  {
    a: string;
    b: number;
    c: undefined;
}
type RecordData2 = Record<'a' | 'b', RecordData1> // { a:RecordData1, b:RecordData1 }

/********************原生实现***************************/

type MyRecord<T extends string | number | symbol, U> = {  
    [P in T]: U; 
}
// 说明
// T extends string | number | symbol , 此时T为联合类型
// 故此在上面的例子中 [p in k] === [p in 'a' | 'b']
type PickData3 = MyRecord<'a' | 'b', RecordData1> 
 

6、Exclude

比较T、U两个泛型,只取T中U所没有的。

type A<T> = T extends string ? number : boolean // 如果T是string,那么就是number类型,否则就是boolean类型
type A1 = A<string>     // A1 = A<number>
type A2 = A<string | number> // A2 = A<number | boolean>

// Exclude,代表只能取T独有的属性
type B2 = Exclude<"a" | "b" | "d", "b" | "c"> // B2 = 'a' | 'd'

/******************原生实现,等价于**************/

type B<T, U> = T extends U ? never : T; 
type B1 = B<"a" | "b" | "d", "b" | "c"> // B1 = 'a' | 'd'
// 解析
// B<"a" | "b" | "c", "b" | "c">  ===  B<'a','b' | 'c'>  | B<'b','b' | 'c'>  | B<'d','b' | 'c'>  

7、Extract

比较T、U两个泛型,只取T、U的交集。

type Data4 = {
    'a': string
    'b': string
}
type Data5 = {
    'a': string
    'c': string
}

type Data7 = Data4 | Data5
type Data8 = Data4

type Test3 = Extract<Data7,Data4> // Data4

/******************原生实现,等价于**************/

type MyExtract<T, U> = T extends U ? T : never;
type Test4 = MyExtract<Data7,Data4> // Data4

declare编写声明文件

全局文件|对象的声明

背景:

你的html文件里面引用了一个全局的js文件`globalA`,但是当你在使用ts文件引用`globalA`的方法时会报错。
因为你的ts项目并不认识它`globalA`

//globalA.js源代码
function globalA(){}
globalA.version = '1.0.0'
globalA.fn1 = function(){}

解决方法,使用关键字declare,并且声明一个同名但后缀为.d.ts的文件

// 在项目里面创建一个globalA.d.ts文件,内容如下
declare function globalA(options: globalA.Options): void;
declare namespace globalA {
    const version: string
    function fn1(): void
    interface Options {
        [key: string]: any
    }
}

导入对象(module|umd)的声明

背景:

你的项目引用了一个module.exports导出的对象或者第三方包moduleA,这个文件使用js编写的。
但是当你在使用ts文件引用`globalA`的方法时会报错。
因为你的ts项目并不认识它`globalA`

// moduleLib.js文件源码
function moduleLib(options) {
    console.log(options)
}
moduleLib.version = '1.9.0';
moduleLib.doSomething = ()=>{
    console.log('do')
}

module.exports = moduleLib

// umdLib.js文件源码
((global, factory) => {
    //如果 当前的上下文有define函数,并且AMD  说明处于AMD 环境下
    if (typeof define === 'function' && define.amd) {
        define(factory);
    }
    else if (typeof exports === 'object') {//commonjs
        modules.exports = factory()
    }
    else {
        global.umdLib = factory() //直接挂载成 windows 全局变量 
    }
})(this, () => {
    //本模块的定义
    return {
        version:'1.0.0',
        doSomething(){}
    }
})

解决方法,使用关键字declare,并且声明一个同名但后缀为.d.ts的文件

// 与moduleLib.js的同一目录下,新建 moduleLib.d.ts 文件,源码如下
declare function moduleLib(options:string):void;
declare namespace moduleLib {
    const version:string
    function doSomething():void
}
export = moduleLib

// umdLib.js的同一目录下,新建 umdLib.d.ts 文件,源码如下
declare function umdLib(options:string):void;
declare namespace umdLib {
    const version:string
    function doSomething():void
}
export = umdLib

给第三方库新增自定义方法

import m from "moment"
declare module "moment" {
    export function myFunction():void
}
m.myFunction = ()=>{}

dom事件类型声明

使用断言 as

function removeDom(event:Event) {
  const target = event.target as HTMLSpanElement;
}

定义时间类型

// 第一种
let a: number;
a = window.setTimeout(function() {}, 0);

// 第二种
const timer: ReturnType<typeof setTimeout> = 
setTimeout(() => '', 1000);

第三方变量类型声明方法

declare学习资料

declare let process:any;

vsc设置ts中文

blog.csdn.net/qq_43869822…

常用的类型声明

react

函数组件中的Children

interface Props { children:React.ReactNode, }

window

定时器

let timer:Number = window.setTimeout(()=>{},300)

dom

定义事件类型(React)

  • ClipboardEvent<T = Element> 剪贴板事件对象
  • DragEvent<T = Element> 拖拽事件对象
  • ChangeEvent<T = Element> Change 事件对象
  • KeyboardEvent<T = Element> 键盘事件对象
  • MouseEvent<T = Element> 鼠标事件对象
  • TouchEvent<T = Element> 触摸事件对象
  • WheelEvent<T = Element> 滚轮事件对象
  • AnimationEvent<T = Element> 动画事件对象
  • TransitionEvent<T = Element> 过渡事件对象
function onPushInput(e ?:React.MouseEvent){
    
}

input的更改

input的value的更改需要用state来保存,同时定义onChange事件来时时显示更改的内容。

const [wechat, setWechat] = useState("aaa");
// 函数定义区
function onHandleChange(event:React.ChangeEvent<HTMLInputElement>) {
setWechat(event.target.value)
}
<input
value={wechat}
onChange={onHandleChange}
type="text"
placeholder="填写你的微信号"
ref={inputEle}
/>