摘自coderwhy的ts教程
单个类型
类型推导
- let进行类型推导, 推导出来的通用类型
- const进行类型推导, 推导出来的字面量类型
数组类型注解
let nums: Array<number> = [123, 321, 111]
let names: string[] = ["abc", "cba", "nba"]
函数类型
- 定义函数参数和返回值
// 定义对象类型
type LyricType = {
time: number
text: string
}
// 歌词解析工具
function parseLyric(lyric: string): LyricType[] {
const lyrics: LyricType[] = []
lyrics.push({ time: 1111, text: "天空想要下雨" })
return lyrics
}
- 匿名函数最好不要添加类型注解
const names: string[] = ["abc", "cba", "nba"]
names.forEach(function(item, index, arr) {
console.log(item, index, arr)
})
unknown
- unknown类型 必须进行类型的校验(缩小), 才能根据缩小之后的类型, 进行对应的操作
let foo: unknown = "aaa"
foo = 123 // 赋值操作不会报错 但如果是 foo.length这种会报错
if (typeof foo === "string") { // 类型缩小
console.log(foo.length, foo.split(" "))
}
void
- 一个函数没有返回值, 那么返回值的类型就是void类型
// 1.定义要求传入的函数的类型
type ExecFnType = (...args: any[]) => void
// 2.定义一个函数, 并且接收的参数也是一个函数, 而且这个函数的类型必须是ExecFnType
function delayExecFn(fn: ExecFnType) {
setTimeout(() => {
fn("why", 18)
}, 1000);
}
// 3.执行上面函数, 并且传入一个匿名函数
delayExecFn((name, age) => {
console.log(name, age)
})
tuple元组
- 数组里每个位置类型不同
- 常用于函数返回多个值时,指明返回值类型
const info3: [string, number, number] = ["why", 18, 1.88]
const value2 = info3[2]
// 在函数中使用元组类型是最多的(函数的返回值)
function useState(initialState: number): [number, (newValue: number) => void] {
let stateValue = initialState
function setValue(newValue: number) {
stateValue = newValue
}
return [stateValue, setValue]
}
const [count, setCount] = useState(10)
console.log(count)
setCount(100)
类型断言
- xx as 类型
- 断言只能断言成更加具体的类型, 或者 不太具体(any/unknown) 类型
const imgEl = document.querySelector(".img") as HTMLImageElement
imgEl.src = "xxx"
imgEl.alt = "yyy"
非空断言
- 使用含有 可选属性的对象类型 对可选属性直接操作时
// 可选属性
interface IPerson {
name: string
age: number
friend?: {
name: string
}
}
const info: IPerson = {
name: "why",
age: 18
}
// 访问属性: 可选链: ?.
console.log(info.friend?.name)
// 属性赋值:
// 解决方案一: 类型缩小
if (info.friend) {
info.friend.name = "kobe"
}
// 解决方案二: 非空类型断言(有点危险, 只有确保friend一定有值的情况, 才能使用)
info.friend!.name = "james"
字面量类型
- const基本类型,即被认为是字面量类型
- 常和联合类型搭配用,锁定值的可选范围
- 如果要用变量填充,靠断言得了
const name: "why" = "why"
const name = "why"//和上面等价
//字面量联合
type MethodType = "get" | "post"
function request(url: string, method: MethodType) {
}
request("http://codfasda.com/api/aaa", "post")
//-----------------------------------------
const info = {
url: "xxxx",
method: "post"
}
// 下面的做法是错误: info.method获取的是string类型
request(info.url, info.method)
// 解决方案一: info.method进行类型断言
request(info.url, info.method as "post")
// 解决方案二: 直接让info对象类型是一个字面量类型
const info2: { url: string, method: "post" } = {
url: "xxxx",
method: "post"
}
// 解决方案三 (const 声明的变量 就是字面量类型,对象不太一样 还得 as const)了解即可
const info2 = {
url: "xxxx",
method: "post"
} as const
request(info2.url, info2.method)
类型复合
联合类型
function printID(id: number | string) {
console.log("您的ID:", id)
// 类型缩小
if (typeof id === "string") {
console.log(id.length)
} else {
console.log(id)
}
}
printID("abc")
printID(123)
类型别名
type IDType = number | string
function printID(id: IDType) {
console.log(id)
}
type PointType = { x: number, y: number, z?: number }
function printCoordinate(point: PointType) {
console.log(point.x, point.y, point.z)
}
接口
interface PointType2 {
x: number
y: number
z?: number
}
别名 和 接口 的区别
结论:如果是非对象类型的定义使用type, 如果是对象类型的声明那么使用interface
- type类型使用范围更广, 接口类型只能用来声明对象
- 声明对象时, interface同名会合并。 type不允许两个相同名称的别名同时存在
- interface支持继承
interface IPerson {
name: string
age: number
}
interface IKun extends IPerson {
kouhao: string
}
const ikun1: IKun = {
kouhao: "你干嘛, 哎呦",
name: "kobe",
age: 30
}
交叉类型
- 两种(多种)类型要同时满足
type NewType = number & string // 没有意义 推断出来是never
interface IKun {
name: string
age: number
}
interface ICoder {
name: string
coding: () => void
}
type InfoType = IKun & ICoder
// info必须含有这俩接口的所有属性,不然报错
const info: InfoType = {
name: "why",
age: 18,
coding: function() {
console.log("coding")
}
}
和它相对的是 联合类型 type ID = number | string
类型缩小
变量是联合类型,且具体处理时要缩小到某个类型时 进行下面这些操作
- typeof
- instanceof
- === / !==
- switch
- key in obj 【obj具有的属性不确定时】
// 1.typeof: 使用的最多
function printID(id: number | string) {
if (typeof id === "string") {
console.log(id.length, id.split(" "))
} else {
console.log(id)
}
}
// 2.===/!==: 方向的类型判断
type Direction = "left" | "right" | "up" | "down"
function switchDirection(direction: Direction) {
if (direction === "left") {
console.log("左:", "角色向左移动")
} else if (direction === "right") {
console.log("右:", "角色向右移动")
} else if (direction === "up") {
console.log("上:", "角色向上移动")
} else if (direction === "down") {
console.log("下:", "角色向下移动")
}
}
// 3. instanceof: 传入一个日期, 打印日期
function printDate(date: string | Date) {
if (date instanceof Date) {
console.log(date.getTime())
} else {
console.log(date)
}
// if (typeof date === "string") {
// console.log(date)
// } else {
// console.log(date.getTime())
// }
}
// 4.in: 判断是否有某一个属性
interface ISwim {
swim: () => void
}
interface IRun {
run: () => void
}
function move(animal: ISwim | IRun) {
if ("swim" in animal) {
animal.swim()
} else if ("run" in animal) {
animal.run()
}
}
const fish: ISwim = {
swim: function() {}
}
const dog: IRun = {
run: function() {}
}
move(fish)
move(dog)
函数类型
基础声明
- 当用函数变量时 (函数作为参数/变量当函数)最好用type定义函数类型
- 函数类型要求的参数多,但函数实例 少参数也没事 调用时多传入的参数被忽略
- 类型定义的函数,只能被多传参,不能少传参
type CalcType = (num1: number, num2: number) => number
const sumS:CalcType=(num1)=>{
return num1
}
function sumT(num1: number, num2: number) {
return num1 + num2
}
function mul(num1: number, num2: number) {
return num1 * num2
}
function calc(calcFn: CalcType) {
const num1 = 10
const num2 = 20
const res = calcFn(num1, num2)
console.log(res)
}
calc(sumS)
calc(sumT)
calc(mul)
可选参数
// 可选参数类型是什么? number | undefined 联合类型
function foo(x: number, y?: number) {
if (y !== undefined) {
console.log(y + 10)
}
}
foo(10)
foo(10, 20)
默认值
// 1.有默认值的情况下, 参数的类型注解可以省略
// 2.有默认值的参数, 是可以接收一个undefined的值
function foo(x: number, y = 100) {
console.log(y + 10)
}
foo(10)
foo(10, undefined)
foo(10, 55)
剩余参数
function foo(...args: (string | number)[]) {
}
foo(123, 321)
foo("abc", 111, "cba")
函数重载
- 当函数的参数类型和返回值类型 有多种对应关系时用
// 1.先编写重载签名
function add(arg1: number, arg2: number): number
function add(arg1: string, arg2: string): string
// 2.编写通用的函数实现
function add(arg1: any, arg2: any): any {
return arg1 + arg2
}
add(10, 20)
add("aaa", "bbb")
联合类型
- 也是针对参数类型不唯一的情况,能用联合类型的场景尽量使用联合类型 不用函数重载
function getLength(arg: string | any[]) {
return arg.length
}
函数中的this
- 没有对TS进行特殊配置的情况下, this是any类型
- //比较复杂 用到的时候再看