TS

类型定义

基础类型

  • 标注类型:let age1: number = 18
  • 常用类型:

    • 原始类型:`number/string/boolean/null/undefined/symbol
    • 对象类型:object(包括,数组、对象、函数等对象)
      • 数组:let strings: Array<string> = ['a', 'b', 'c']
    • 联合类型 let arr: (number | string)[] = [1, 'a', 3, 'b']

      例如:对于定时器let timer:number|null = null

  • 类型别名:type s = string\ type MyArr = (number | string) []

函数

  • 函数基础
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 普通函数
function 函数名(形参1: 类型=默认值, 形参2:类型=默认值): 返回值类型 { }

// 箭头函数
const 函数名(形参1: 类型=默认值, 形参2:类型=默认值):返回值类型 => { }

// 函数声明
function add(num1: number, num2: number): number {
return num1 + num2
}

// 箭头函数
const add = (num1: number=10, num2: number=20): number => {
return num1 + num2
}

  • 函数类型别名
1
2
3
type Fn = (n1:number,n2:number) =>number //定义Fn为类型别名
const add1 : Fn = (a,b)=>{return a+b }

注意:如果什么都不写,此时,add 函数的返回值类型为: void
但是如果指定 返回值类型为 undefined,此时,函数体中必须显示的 return undefined 才可以

  • 可选参数
    标识
1
2
3
function mySlice(start?: number, end?: number): void {
console.log('起始索引:', start, '结束索引:', end)
}

对象

  • 对象新建并赋值
1
2
3
4
5
const goodItem:{name: string, price: number, func: ()=>string,email?: string }  = {
name: '手机',
price: 2000,
func:function(){ return '打电话' }
}
  • 定义对象
1
2
3
4
5
type Person = {
name: string
age: number
sayHi(): void
}

此后你可以在如下地方使用Person类:

1
2
3
4
5
6
7
8
9
10
// 使用类型别名作为对象的类型:
let person: Person = {
name: '小花',
age: 18
sayHi() {}
}

function f1 (p: Persion) :void {

}

接口

基本和类相似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface IGoodItem  {
name: string, price: number, func: ()=>string
}


const good1: IGoodItem = {
name: '手表',
price: 200,
func: function() {
return '看时间'
}
}

const good2: IGoodItem = {
name: '手机',
price: 2000,
func: function() {
return '打电话'
}
}

接口,只能为对象指定类型。它可以继承
一般来讲,能用type就用类

接口其他
  • ?标识可选
  • 可以调用接口本身属性
1
2
3
4
5
6
7
interface UserItem {
name: string
age: number
enjoyFoods: string[]
// 这个属性引用了本身的类型
friendList: UserItem[]
}
接口继承
1
2
3
4
5
6
7
8
9
10
11
interface UserItem {
name: string
age: number
enjoyFoods: string[]
friendList: UserItem[]
}

// 这里继承了 UserItem 的所有属性类型,并追加了一个权限等级属性
interface Admin extends UserItem {
permissionLevel: number
}

如果觉得这个 Admin 类型不需要记录这么多属性,也可以在继承的过程中舍弃某些属性,通过 Omit 帮助类型来实现,Omit 的类型如下:

1
type Omit<T, K extends string | number | symbol>

其中 T 代表已有的一个对象类型, K 代表要删除的属性名,如果只有一个属性就直接是一个字符串,如果有多个属性,用 | 来分隔开,下面的例子就是删除了两个不需要的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface UserItem {
name: string
age: number
enjoyFoods: string[]
friendList?: UserItem[]
}

// 这里在继承 UserItem 类型的时候,删除了两个多余的属性
interface Admin extends Omit<UserItem, 'enjoyFoods' | 'friendList'> {
permissionLevel: number
}

// 现在的 admin 就非常精简了
const admin: Admin = {
name: 'Petter',
age: 18,
permissionLevel: 1,
}

元组

确切标识数组的每个元素的类型和长度

let position: [number, number] = [39.5427, 116.2317]:限定了每一个元素的类型,以及长度只能为2 (该示例中,元素有两个元素,每个元素的类型都是 number)

1
2
3
4
5
6
7
8
9
function useState(n: number): [number, (number)=>void] {
const setN = (n1) => {
n = n1
}
return [n, setN]
}
// 限定了返回的第二个元素为函数

const [num ,setNum] = useState(10)

字面量

只能且只能是字面量初始化的内容。不能更改为其他

1
2
3
4
5
const str2 = 'hello 武汉' //str2无法更改,也算字面量
let a:'abc' = 'abc' //a是'abc'字面量类型的,只能取abc

type Direction = 'up' | 'down' | 'left' | 'right'
let d:Direction ='up' //d是字面量类型的,只能上面四选择一

枚举

枚举是可以同时存在的。

1
2
3
4
5
6
7
8
9
10
11
12
13
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}

//注意访问的时候需要区别
function fn(msg: Direction): void {
// ...
}

fn(Direction.Down)

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum Gender {
girl,
boy
}
type User = {
name: string,
gender: Gender
}

const u1: User = {
name: '小花',
gender: Gender.girl
}

any类型

当类型设置为 any 时,就取消了类型的限制。

类型方法

类型断言

案例1:

1
2
const box = document.getElementById('img') as HTMLImageElement 
box.src

document.getElementById方法返回值的类型是 HTMLElement,其不存在src的属性,可以断言为更细致的类型

案例2:

1
2
3
4
5
6
type User = {
name: string,
age: number
}

const u1 = {} as User

在设置初始值时候,结果是用ajax拿到的,可以这样设置。

TypeOf

typeof 操作符,用来在 JS 中获取数据的类型

可以使用type 类型 = typeof 常量简化类型书写,我可以直接获取res的类型

1
2
3
4
5
6
7
8
9
10
const res = { name: '小花', city: '武汉',  skills: ['js', 'css'] }//ajax请求

type Stu = typeof res // 直接变为res的类型

function fn(obj:Stu) {
// 这里写 obj. 就会有提示
obj.skills
}

fn(res)

交叉类型

1
2
3
4
5
6
7
8
9
interface Person{name:string}
interface Contact{phone:string}
type PersonDetail=Person & Contact
//type PersonDetail={name:string;phone:string}; 等同于上方
let obj:PersonDetail={
name:"IT飞牛",
phone:"13312332123"
};

使用交叉类型后,新的类型PersonDetail就同时具备了PersonContact的所有的属性类型。
注意:对于同名属性之间,不会报错(使用接口继承会报错)

泛型

泛型,顾名思义,就是可以适用于多个类型
使用类型变量比如T帮助我们捕获传入的类型,之后我们就可以继续使用这个类型。

泛型函数

语法:在函数名称的后面写 <>(尖括号),尖括号中添加类型变量

1
function fn<T>(value: T): T { return value }

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
// useState它接收一个任意类似的数据,返回一个数组。数组的第一个元素的类型与入参一致; 数组的第二个元素是一个函数,函数的入参类型和返回值类型与useState的入参一致

function useState<T>(p:T): [T,(p:T)=>T] {
const t = (p: T):T => {
return p
}
return [p, t]
}


const arr1 = useState('123')
const arr2 = useState(123)

添加泛型约束

当比如需要获取一个元素的length,但是使用了泛型,那么必须保证他有length才可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//方式1:
function fn<Type>(value: Type[]): Type[] {
console.log(value.length)
return value
}//Type[]标识Type 类型的数组,则一定有length


//方式2:使用接口,继承T extends——通用
// 创建一个接口
interface ILength { length: number }

// T extends ILength 添加泛型约束
function fn<T extends ILength>(value: T): T {
console.log(value.length)
return value
}

fn('abc') // Ok
fn([1,2,3]) // Ok

多个类型

1
2
3
4
5
6
7
function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}

let person = { name: 'jack', age: 18 }
getProp(person, 'name')

  1. 添加了第二个类型变量 Key,两个类型变量之间使用 , 逗号分隔。
  2. keyof 关键字接收一个对象类型,生成其键名称(可能是字符串或数字)的联合类型

    本示例中 keyof Type 实际上获取的是 person 对象所有键的联合类型,也就是:'name' | 'age'

  3. 类型变量 Key 受 Type 约束,可以理解为:Key 只能是 Type 所有键中的任意一个,或者说只能访问对象中存在的属性

泛型接口

1
2
3
4
5
6
interface MyArray<T> {
length: T,
push(n: T):void,
pop():T,
reverse():T[]
}

泛型工具

1. Partial

构造(创建)一个类型,将 Type 的所有属性设置为可选。

2. Readonly

构造(创建)一个类型,将 Type 的所有属性设置为只读

3. Pick

Pick<Type, Keys>从 Type 中选择一组属性来构造新类型。

1
2
3
4
5
6
7
8
9
type Props =  {
id: string
title: string
children: number[]
}

type PartialProps = Partial<Props>
type ReadonlyProps = Readonly<Props>
type PickProps = Pick<Props, 'id' | 'title'>

构造出来的新类型:

  • PartialProps 结构和 Props 相同,但所有属性都变为可选的。
  • ReadonlyProps 结构和 Props 相同,但所有属性都变为只读的。
  • 构造出来的新类型 PickProps,只有 id 和 title 两个属性类型。
4. Record

Record<Keys,Type>:构造一个对象类型,属性键为keys,属性类型为Type

1
2
3
4
5
let arg4: Record<number, string> = {
1: "a",
2: "b",
3: "c",
};

类型声明

.d.ts文件中,包含类型信息的类型声明文件


补充

tsconfig

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
{
// 编译选项
"compilerOptions": {
// 生成代码的语言版本:将我们写的 TS 代码编译成哪个版本的 JS 代码
// 命令行: tsc --target es5 11-测试TS配置文件.ts
"target": "es5",
// 指定要包含在编译中的 library
"lib": ["dom", "dom.iterable", "esnext"],
// 允许 ts 编译器编译 js 文件
"allowJs": true,
// 跳过类型声明文件的类型检查
"skipLibCheck": true,
// es 模块 互操作,屏蔽 ESModule 和 CommonJS 之间的差异
"esModuleInterop": true,
// 允许通过 import x from 'y' 即使模块没有显式指定 default 导出
"allowSyntheticDefaultImports": true,
// 开启严格模式
"strict": true,
// 对文件名称强制区分大小写 Demo.ts
"forceConsistentCasingInFileNames": true,
// 为 switch 语句启用错误报告
"noFallthroughCasesInSwitch": true,
// 生成代码的模块化标准
"module": "esnext",
// 模块解析(查找)策略
"moduleResolution": "node",
// 允许导入扩展名为.json的模块
"resolveJsonModule": true,
// 是否将没有 import/export 的文件视为旧(全局而非模块化)脚本文件
"isolatedModules": true,
// 编译时不生成任何文件(只进行类型检查)
"noEmit": true,
// 指定将 JSX 编译成什么形式
"jsx": "react-jsx"
},
// 指定允许 ts 处理的目录
"include": ["src"]
}