TypeScript基础&实战[未完]

基础篇

强类型和弱类型
动态类型和静态类型

1. 基本类型

数据类型

  • boolean number
    string
    array
    function
    object
    symbol
    undefined
    null
  • 新增 void
    any
    never
    元祖
    枚举
    高级类型

类型注解
相当于强类型语言中的类型声明
语法:(函数/变量):type

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
// 原型类型
let bool: boolean = true
let num: number = 123
let str: string = 'abc'

// 数组
let arr1: number[] = [1,2,3]
let arr2: Array<number> = [1,2,3]
let arr3: Array<number | string> = [1,2,3,'123']

// 元组 限制类型和个数
let tuple: [number,string] = [1,'1']
tuple.push(2) //允许插入
// console.log(tuple[2]) // 但是不可以访问

// 函数 ):number 返回值的类型
let add = (x:number, y:number):number => x+y
let compute: (x:number,y:number) => number
compute = (a,b) => a+b

// 对象
let obj: {x:number,y:number} = {x:1,y:2}
obj.x = 3

// symbol
let s1: symbol = Symbol()
let s2 = Symbol()

// undefined,null
let un:undefined = undefined
let nu: null = null
// num = undefined //可配置 strictNullChecks
// num = null
let n : number | undefined | null = 1

// void 没有任何返回值的类型
let noReturn = () => {}

// any
let x
x=1
x='1'
x=()=>{}

// never 永远不会有返回值的类型 死循环
let error = () =>{
throw new Error('error')
}
let endless = () =>{
while(true) {}
}

2. 枚举类型(一组具有名字的常量集合)

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
52
53
54
55
56
57
58
/**
* 枚举类型
*/

// 数字枚举 0,1,2,3,4,5 反向映射
enum Role{
Reporter = 1,
Developer,
Maintainer,
Owner,
Guest
}

// 字符串枚举
enum Message {
Success = '恭喜你,成功了',
Fail = '抱歉,失败了'
}

// 异构枚举 混用 不建议使用
enum Answer {
N,
Y = 'YES'
}

// 枚举成员
enum Char{
// const
a,
b=Char.a,
c=1+3,

// computed 编译阶段不计算 运行阶段才计算 在此后声明的常量必须初始化值
d=Math.random(),
e='123'.length
}

// 常量枚举
const enum Month {
Jan,
Feb,
Mar
}

// 枚举类型
enum E { a,b }
enum F { a = 0, b=1}
enum G { a='apple', b='banana'}

let e:E = 3
let f:F = 3

let e1:E.a
let e2:E.b
let e3:E.a

let g1:G
let g2:G.a

3. 接口

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
52
53
54
55
56
57
58
59
/**
* 对象类型接口
*/
interface List {
id:number,
name:string
}

interface Result {
data: List[]
}

function render(result: Result){
result.data.forEach((value)=>{
console.log(value.id,value.name)
})
}

let result = { // 第0种,赋值变量
data:[
{id:1,name:'1'},
{id:2,name:'2'}
]
}

render(result)

// 类型断言 as Result 绕过类型检查 第一种
render({
data:[
{id:1,name:'1',sex:'women'},
{id:2,name:'2'}
]
} as Result)
//or 第二种
render(<Result>{
data:[
{id:1,name:'1',sex:'women'},
{id:2,name:'2'}
]
})
//or 第三种
// interface List {
// readonly id:number, 只读属性
// name:string
// [x:string]:any
// age?: number 可选属性 可以有也可以没有
// }

// 数字索引接口
interface StringArray {
[index:number]:string
}
let chars:StringArray = ['A','B']

// 字符串索引接口
interface Names {
[index:string]:string
}
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
/**
* 函数类型接口
*/

// let add2: (x:number, y:number) => number
// interface Add {
// (x:number,y:number):number
// }

// 类型别名
type Add = (x:number,y:number) => number

let add2:Add = (a,b)=> a+b

// 混合接口
interface Lib{
():void;
version: string;
doSomething():void;
}
function getLib(){
let lib:Lib =(()=>{}) as Lib; //类型断言
lib.version = '1.0';
lib.doSomething = () =>{}
return lib
}
let lib1 = getLib() //可创建多个实例
lib1()
lib1.doSomething()

函数相关知识点:可选参数、函数重载、默认值、剩余参数

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
// 可选参数 ? 必须位于必选参数后面;必须参数不能位于可选参数之后
function add5(x:string,y?:number){
return y?x+y:x;
}
add5('1')

// 默认值
function add6(x:number,y=0,z:number,q=1){
return x+y+z+q;
}

// 剩余参数
function add7(x:number,...rest:number[]){
return x+rest.reduce((pre,cur)=> pre+cur) //reduce求和
}
add7(1,2,3,4,5)

// 函数重载
function add8(...rest: number[]):number
function add8(...rest: string[]):string
function add8(...rest: any[]):any{
let first = rest[0]
if(typeof first === 'string'){
return rest.join('')
}else if(typeof first === 'number'){
return rest.reduce((pre,cur)=> pre+cur)
}
}
console.log(add8(1,2,3))
console.log(add8('a','b','c'))

4. 类:继承和成员修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 类
class Dog{
constructor(name:string){ // 构造函数 可以设置为受保护 protected constructor() 可以被继承
this.name = name
}
name:string
run(){}
private pri(){} //私有成员 不能在实例和子类中调用
protected pro(){} //受保护成员 不能在实例中调用 可以在子类中调用
readonly legs: number = 4 // 只读
static food:string ='boon' //静态成员 只能通过类名调用 可以被继承
}

let dog = new Dog('wangwang')
console.log(Dog.food)

// 类的继承
class Husky extends Dog{
constructor(name:string,public color:string){ //构造函数 的参数 可以添加修饰符 public 将参数变成实例的属性
super(name)
this.color = color
}
// color:string
}

5. 类:抽象类和多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// this 链式调用
class WorkFlow{
step1(){
return this
}
step2(){
return this
}
}
new WorkFlow().step1().step2()

// 子类
class Myflow extends WorkFlow{
next(){
return this
}
}
new Myflow().next().step1().next().step2()

6.类与接口

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
// 接口的继承 多个接口合并
interface Man extends Human{
run(): void
}
interface Child{
cry():void
}
interface Boy extends Man,Child{}

let boy: Boy={
name:'123',
run(){},
eat(){},
cry(){}
}

class Auto{
state = 1
// private state2 = 0 // 非子类 C不能继承 私有属性
}
interface AutoInterface extends Auto{

}
class C implements AutoInterface{
state = 1
}
class Bus extends Auto implements AutoInterface{

}

7.泛型

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
/**泛型 
* 不预先确定的数据类型,具体的类型在使用的时候才能确定
* 1.函数和类可以轻松的支持多种类型,增强程序的扩展性
* 2.不必谢多条函数重载,冗长的联合类型声明,增强代码可读书生
* 3.灵活控制类型之间的约束
* */
function log<T>(value:T):T{
console.log(value)
return value
}
log<string[]>(['a','b'])
log(['a','b'])

// 泛型接口
interface Log{
<T>(value: T):T
}
let myLog: Log = log
myLog('1')

// 泛型类 和 泛型约束
class LogClass<T>{
run(value:T){
console.log(value)
return value
}
}
let log1 = new LogClass<number>() //指定类型
log1.run(1)
let log2 = new LogClass() //不指定
log2.run('1')

// 泛型约束
interface Length{
length:number
}
function logRule<T extends Length>(value:T){
console.log(value,value.length)
return value
}
logRule([1])
logRule('123')
logRule({length:1})

8.1.类型检查机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 类型推断 从右向左
let a = 1
let b = [1]

let c = (x=1) => x+1

// 类型推断 从左到右 上下文推断
window.onkeydown = (event) =>{
console.log(event)
}

interface Foo{
bar:number
}
// let foo = {} as Foo 遗漏bar
let foo:Foo = {
bar:1
}

8.2.类型兼容性

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// 类型的兼容性问题
// X兼容Y:X目标类型 = Y源类型
// 结构之间兼容:成员少的兼容成员多的
// 函数之间兼容:参数多的兼容参数少的
let s: string = 'a'
s = 'b'

// 接口兼容性
interface X{
a:any
b:any
}
interface Y{
a:any
b:any
c:any
}
let x1:X={a:1,b:2}
let y1:Y = {a:1,b:2,c:3}
x1 = y1

// 函数兼容性
type Handler = (a:number,b:number) => void
function hof(handler:Handler){
return handler
}
//1参数个数
let handler1 = (a:number) =>{}
hof(handler1)
let handler2 = (a:number,b:number,c:number) =>{}
// hof(handler2) 此就不兼容 多了C

// 可选参数和剩余参数
let a1 = (p1:number,p2:number) =>{}
let b1 = (p1?:number,p2?:number) =>{}
let c1 = (...args:number[]) =>{}
a1 = b1
a1 = c1
b1 = c1
b1 = a1
c1 = a1
c1 = b1

//2参数类型
let handler3 = (a:string) =>{}
// hof(handler3)
interface Point3D{
x:number
y:number
z:number
}
interface point2D{
x:number
y:number
}
let p3d = (point: Point3D) =>{}
let p2d = (point: point2D) =>{}
p3d = p2d
p2d = p3d

//3 返回值类型 成员少的兼容成员多的
let f1 = () => ({name:'Alice'})
let f2 = () => ({name:'Alice',loacation:'beijing'})
f1=f2

function overload(a:number,b:number):number
function overload(a:string,b:string):string
function overload(a:any,b:any):any {}

// 枚举兼容性
enum Fruit {Apple,Banana}
enum Color {Red,Yellow}
let fruit:Fruit.Apple = 3
let no:number = Fruit.Apple
// let color:Color.Red = Fruit.Apple 不兼容

//类兼容性
class Ab{
constructor(p:number,q:number){}
id:number = 1
}
class Bb{
static s=1
constructor(p:number){}
id:number=2
}
let aa = new Ab(1,2)
let bb = new Bb(1)

aa = bb // 兼容 因为都有ID,静态成员不做比较 如果有私有成员,就不兼容
bb = aa
// 如果有私有成员,子类就兼容
class CC extends Ab{}
let cc = new CC(1,2)
aa=cc
cc=aa

//泛型兼容性
interface Empty<T>{
value:T
}
let obj1:Empty<number> = {}
let obj2:Empty<string> = {}
// obj1 = obj2 不兼容

//如果两个泛型定义相同,没有指定参数,是兼容的
let logx1 = <T>(x:T):T=>{
console.log('x')
return x
}
let logx2 = <T>(y:T):T=>{
console.log('y')
return y
}
logx1 = logx2

8.3.类型保护机制

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
52
53
54
55
56
57
58
59
// 类型保护机制
// TS能够在特定的区块中保证变量属于某种确定的类型
// 可以在区块中放心的使用类型的属性,并且调用类型的方法
enum Type{Strong,Week}
class Java{
helloJava(){
console.log('HelloJava')
}
java:any
}
class JavaScript{
helloJavaScript(){
console.log('JavaScript')
}
javascript:any
}
function getLanguage(type:Type,x:string | number){
let lang = type ===Type.Strong ? new Java():new JavaScript()
// 1 比较麻烦的判断
// if((lang as Java).helloJava){
// (lang as Java).helloJava()
// }else{
// (lang as JavaScript).helloJavaScript()
// }

//2 使用instanceof属于哪个类
// if(lang instanceof Java){
// lang.helloJava()
// }else{
// lang.helloJavaScript()
// }

// 3 in 判断是属于某个对象
// if('java' in lang){
// lang.helloJava()
// }else{
// lang.helloJavaScript()
// }

// 4 typeof 判断
// if(typeof x==='string'){
// x.length
// }else{
// x.toFixed(2)
// }

// 5 使用函数isJava
if(isJava(lang)){
lang.helloJava()
}else{
lang.helloJavaScript()
}
return lang
}

function isJava(lang:Java | JavaScript):lang is Java{ //返回值为类型伪词
return (lang as Java).helloJava !== undefined

}

工程篇

1.ES6 commonjs

2.tsconfig.json

文件选项 files include exclude
编译选项 complierOptions 【重点】
工程引用

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
{
"compilerOptions": {
"allowUnreachableCode": true, // 不报告执行不到的代码错误。
"allowUnusedLabels": false, // 不报告未使用的标签错误
"alwaysStrict": false, // 以严格模式解析并为每个源文件生成 "use strict"语句
"baseUrl": ".", // 工作根目录
"experimentalDecorators": true, // 启用实验性的ES装饰器
"jsx": "react", // 在 .tsx文件里支持JSX
"sourceMap": true, // 是否生成map文件
"module": "commonjs", // 指定生成哪个模块系统代码
"noImplicitAny": false, // 是否默认禁用 any
"removeComments": true, // 是否移除注释
"types": [ //指定引入的类型声明文件,默认是自动引入所有声明文件,一旦指定该选项,则会禁用自动引入,改为只引入指定的类型声明文件,如果指定空数组[]则不引用任何文件
"node", // 引入 node 的类型声明
],
"paths": { // 指定模块的路径,和baseUrl有关联,和webpack中resolve.alias配置一样
"src": [ //指定后可以在文件之直接 import * from 'src';
"./src"
],
},
"target": "ESNext", // 编译的目标是什么版本的
"outDir": "./dist", // 输出目录
"declaration": true, // 是否自动创建类型声明文件
"declarationDir": "./lib", // 类型声明文件的输出目录
"allowJs": true, // 允许编译javascript文件。
"lib": [ // 编译过程中需要引入的库文件的列表
"es5",
"es2015",
"es2016",
"es2017",
"es2018",
"dom"
]
},
// 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
"include": [
"src/**/*"
],
// 指定一个排除列表(include的反向操作)
"exclude": [
"demo.ts"
],
// 指定哪些文件使用该配置(属于手动一个个指定文件)
"files": [
"demo.ts"
]
}

实战篇

1. 创建工程

手动创建 制作组件 引入组件 修改webpack 修改typeconfig
利用脚手架 sudo npx create-react-app ts-reat-app –typescript NPX为避免全局安装