1. 准备阶段

安装TypeScript基本环境

1
2
3
4
5
6
7
8
9
10
npm i typescript -g
# 生成ts配置文件
tsc --init
# 手动解析ts文件
tsc xxx.ts
# 监视ts 实时转换js文件
- 在vscode里面终端 输入
- ctrl+shift+b
- 监视tsc
- 或者在菜单-终端-运行任务-监视tsconfig.json

类型推断

1
2
3
如果定义的时候没有赋值,不管之后有没有赋值,
都会被推断成 any 类型而完全不被类型检查:
如果定义的时候赋值了 就推断成这个格式

tsconfig

1
2
3
4
5
6
7
8
9
{
"compilerOptions": {
// 开启js提示
"allowJs": true,
// 指定压缩代码生成的目录 随便一个不存在的路径就行
"outDir": "./random",
"declaration": true, // 自动生成 .d.ts 文件 类型校验
}
}

declare

1
2
3
4
5
6
7
8
9
// 全局类型标注
// 声明不存在的sdk 避免报错
declare module '*.css';
declare module '*.less';
declare module '*.png';
interface jQuery {}
declare module 'jquery' {
export = jQuery;
}

2. TS基础

基本类型

数据类型 描述
boolean
number
string 推荐单引号
Array Array || number [ ] || string [ ] || Array
tuple 元组 固定长度的数组
Object 任意的JS对象 但是不能调用其他方法 即便它真的有
any 任意类型
unknown 类型安全的any 区别是any会把别的也推断成any 他只推断自己
null 可以赋给其他类型变量 但如果–strictNullChecks 就只能给自己
undefined 可以赋给其他类型变量 但如果–strictNullChecks 就只能给自己
void 表示没有任何类型 函数没有返回值他的类型就是void
never 没有值 不能是任何值: 用于函数没有返回值 例如只用于报错的函数

其他类型

数据类型 描述
?: 可选属性
!: 非空断言 => ?.
readonly 只读
[xxx:string ]:any 不规定后续内容类型
enum 枚举 只能赋值为 undefined 和 null
元组 let x: [number, string] = [10, “jack”]
| 联合类型 只能同时为一种
& 交叉类型 合并
Partial 可选类型合并 Partial <xxx & xxx>

3. 基本API

定义变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 变量: 数据类型
var hello: string = 'helloworld'
# 对象: {对象属性: 数据类型 , ...} = { xxx}
var user: {name: string, age: number}={ name:'jack',age: 15 }
let obj= {name:string} & {age:number}
// 任意类型 => 泛型
var c:{name:string,[xxx: string]:any};
# 数组
var arr: number[] = [1,2,3]
var arr: Array<number> = [1,2,3]
interface arr {
[index: number]: number
}
// 指定某一个数组下的 每一个对象的属性
dataSource?: [{ [key: number]: Interface }]
// 或者这样
interface TestArr {
username: string,
password: number
}
interface arr {
[xx: number]: TestArr
}
var arr: arr = [{ username: 'ss', password: 555 }]

类型断言

1
2
3
4
5
// 手动指定某一个值的类型
1.as 类型
(someValue as string) React-jsx必须用这个
2.<类型>值
(<string>someValue)

type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# base
type str = string | number;
// 接口也可以用
// type str = 接口1 | 接口2
var str: str = "10"
str = 10
# 限制固定常量
type sex = '男' | '女'
# 函数别名
type newType = (x: number, y: number) => number
function sum(s: number, y: number): number {
return x + y
}
const sum2: newType = sum

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#
// 可选
name?:number
// 默认值
name: string = 20
# 函数的重载
function getInfo(name:string):string;
function getInfo(age:number):string;
function getInfo(s:any):any{
if(typeof s==='string'){
return '我叫:'+s;
}else{
return '我的年龄是'+s;
}
}
console.log(getInfo('张三')); //正确
console.log(getInfo(20)); //正确
// console.log(getInfo(true)); //错误写法 ts编译报错

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 // 用于取值 并限定在一定范围  =>  会被编译成一个双向映射的对象
// 默认从0开始递增 直到枚举进行反向映射
enum Days {
Sun = 3, // 一个设置值 其他也要设置
Mon,
Tue,
Wed,
Thu,
Fri,
Sat
}
let xxx = Days.Sun
# 常量枚举
const dnum xxx {

}

4. inerface

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
# base
interface IPerson {
readonly name: string | number, // 只读
age?: number, // 可选
[propsName: string]: any // 任意属性个数
}
let user: Person = {
name:"zhuangsan",
age: 18,
...
}
# 接口嵌套
interface TestArr {
username: string,
password: number
}
interface arr {
[xx: number]: TestArr
}
var arr: arr = [{ username: 'ss', password: 555 }]
# 函数接口
interface aa {
(name: string, age: number): number
}
const fm:aa = function(name:string,age:number){
return 1
}
# 接口继承
interface 接口内的方法 entends 接口名{ }
# 接口实现
class Car implements 接口名{ }
# 泛型结函数
interface Icreate<T>{
(a:T,b:T):T
}
const a: Icreate<number> = 函数

5. 泛型

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
# 
指不预先指定具体类型 而使用时候再指定 的一种特性
function echo<T>(arg: T): T { return arg }
echo('4') echo<string>('4')
function swap<T, U>(data: [T, U]): [U, T] { }
T[]
# 约束泛型
interface Inter {
length: number
}
function fn<T extends Inter>(a: T): number {
return a.length
}
fn(1) // 报错 数字没有.length 必须要有.length


# 与接口结合
interface Icreate <T,U> {
name:T;
age:U;
}
let test:Icreate<number,string> = {name:5,age="ss"}
# 与函数的结合
interface Icreate {
<T>(name: string, value: T): Array<T>
}
let aaaaaa: Icreate;
aaaaaa = function <T>(name: string, value: T): Array<T> {
return []
}
var aaa: number[] = aaaaaa("zzhang", 5)
# 与类的结合
class Person <T>{
name: T;
constructor(name:T){
this.name = name
}
}
const xxx = new Person<string>('张三')

6. class

js

1
#私有属性

API

1
2
3
4
5
6
# 遍历属性
Object.kes(实例名).forEach(key=>实例名[key])
# 遍历方法
className.prototype 不能通过 forEach遍历 // 构造函数 可以
Object.getOwnPropertyNames([className].prototype)
.forEach(item=>[className].prototype[item])

类表达式

1
2
3
4
5
6
7
8
const aaa = class {
// 匿名
}

const bbb = class ccc {
ccc.name
// 只有内部可以访问ccc
}

4个状态

public

1
实例和父类能都访问

static

1
2
3
4
5
6
7
8
9
// 只能父类点出来
// 类似于直接在 Person.prototype.aaaa = '孙悟空'
// constructor() { this.bbb = 12; }
class Person {
static aaaa: string = ' 孙悟空';
bbb: number = 12;
}
const per = new Person()
console.log(Person.aaaa)

private

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// private    私有的         外界无法访问 不能被继承
为了避免直接修改 class中的属性 产生数据混乱
private 定义属性 拒绝外界访问
同时在class内部 定义 getter setter 向外界开放 获取和修改的方法
内部可以设计 方法的权限
class Person {
_name: string;
private _age: number;
constructor(_name: string, _age: number = 10) {
this._name = _name;
this._age = _age;
}
get age() {
return this._age
}
set age(value: number) {
if (value < 10) {
this._age = value
}
}
}
const per = new Person('张三', 10)
per.age = 200
console.log(per) //10

protected

1
// protected  受保护的       外界无法访问 可以被继承

readonly

1
2
readonly ccc: string = 'ss'
static readonly ccc: string = 'ss'

get set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 手动定义 获取和更改方法 的computed 
// get 定义的 可以直接点出来 不用调方法
// 如果不是关键字 get 就得使用定义的方法修改
class Person {
_name: string;
private _age: number;
constructor(_name: string, _age: number = 10) {
this._name = _name;
this._age = _age;
}
get age() {
return this._age
}
set age(value: number) {
if (value < 10) {
this._age = value
}
}
}
const per = new Person('张三', 10)
per.age = 200
console.log(per) //10

constructor

constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHi() {
console.log('hello')
}
}
const per: Person = new Person('2', 2)
# 或者
class Person {
constructor(public name: string,public age: number) {
}
sayHi() {
console.log('hello')
}
}
const per: Person = new Person('2', 2)

super

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHi() {
console.log('sss');
}
}

class Cat extends Animal {
type: string;
constructor(name: string, age: number, type: string) {
super(name, age);
this.type = type
}
sayHi() {
super.sayHi()
}
}
new Cat('as', 1, 'asd').sayHi()

extends

1
2
子类重写方法 在子类中 会覆盖父类的方法
// 如果要加属性 必须写super 重写属性

implements

1
2
3
4
5
# implements  需要重写属性和方法
class A implements 接口{

}
// 不用定义 super() 可以重写 属性和方法

abstract

1
2
3
4
5
6
7
8
9
10
# 抽象类 禁止被实例化 用来被继承的
abstract class Parent{

}
# 父类指定结构 子类来实现 避免忘记重写方法导致使用默认的方法
// 抽象方法只能以abstract开头 没有方法体
// 只能定义在抽象类里面 子类必须重写
abstract class Parent{
abstract sayHi():void;
}

7. 装饰器

  • 在运行时立即调用 被装饰的声明信息做为参数传入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function Path(name: string) {
    console.log('需要通过柯里化形式拿到参数,默认传入的是target')
    return function (traget: any) {
    console.dir(name, traget.age)
    }
    }

    @Path('zhangsan')
    class Hello {
    public static age: number = 12
    }

8. 高级API

Partial

1
2
// 可选类型
Partial <xxx & xxx>

omit

1
2
3
4
5
6
7
8
// 忽视重写某个属性 
interface A {
a: number;
b: number;
}
interface B extends Omit<A, 'a'> {
a: boolean;
}

Record

1
2
3
4
5
6
7
// 定义一个对象的 key 和 value
type keys = 'A' | 'B' | 'C'
const result: Record<keys, number> = {
A: 1,
B: 2,
C: 3
}

typeof

1
// 自动推断后续的属性

in

1
2
3
4
5
6
7
8
type ChinaMobilePhones = '10086' | '10010' | '10000'
interface ChinaMobile {
name: string;
website: string;
}
type ChinaMobileList = {
[phone in ChinaMobilePhones]: ChinaMobile
}

keyof

1
2
3
4
class Application<T> {
set<T extends keyof keys>(key: T, val: keys[T]) { }
get<T extends keyof keys>(key: T): void { }
}

9. 工具函数

覆盖接口类型

1
2
3
4
5
6
7
8
9
10
# 覆盖接口属性
/**
* Returns object T, but with T[K] overridden to type U.
* @example
* type MyObject = { a: number, b: string }
* OverrideProperty<MyObject, "a", string> // returns { a: string, b: string }
*/
export type OverrideProperty<T, K extends keyof T, U> = Omit<T, K> & { [P in keyof Pick<T, K>]: U };
# 第二种方法
type Modify<T, R> = Omit<T, keyof R> & R;

10. react接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# react组件接口
import React, { FC, ButtonHTMLAttributes, AnchorHTMLAttributes } from 'react'
class Component:FC<泛型> extends React {

}
# react组件props接口
React.ComponentProps<'button'>
# css
React.CSSProperties
# children
React.FunctionComponentElement
# 事件
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
# promise
Promist<string[]>
# 键盘事件
e:React.KeyboardEvent
# ref
React.RefObject<HTMLElement>