TypeScript
参考文章:ts完整版coderwhy笔记
一、初识TypeScript
1.TS是干嘛的
typescript最主要的作用:类型校验
function getLength(str: string | any[]) {
return str.length
}
getLength('sda')
getLength([1123, false, 'sadsda'])
getLength(123) //飘红
TypeScript最终会被编译成JavaScript来运行。我们可以把TypeScript理解成更加强大的JavaScript,不仅让JavaScript更加安全,而且给它带来了诸多好用的好用特性;
2.安装及运行ts文件
ts的安装:
//安装命令:
npm install typescript -g
//查看版本:
tsc --version
运行环境ts-node安装:
//安装ts-node:
npm install ts-node -g
npm install tslib @types/node -g
控制台运行ts文件:
ts-node demo.ts
3.变量的声明
声明了类型后TypeScript就会进行类型检测,声明的类型可以称之为类型注解;
例如声明一个message,类型规定必须是string类型
如果我们给message赋值其他类型的值,那么就会报错
4.变量的类型推断
默认情况想进行赋值时,会将赋值的值的类型,作为前面标识符的类型
let age = 18
// age = 'zzy' 报错
console.log(age)
const height = 1.88 //类型是字面量1.88
console.log(height)
这里要注意,使用let
声明的变量,推断的就是通用类型
使用const
声明的变量,推断出来的是字面量类型
5.JS中的类型声明
在ts中,声明js中的类型怎么写呢?
对于number、string、boolean、null、undefined就直接写
对于数组和对象,要指定每一个具体的类型是什么
const names1: Array<string> = [] // 不推荐(react jsx 中有冲突) <div></div>
const names1: string[] = [] // 推荐
// 在数组中存放不同的类型是不好的习惯
// names2.push('abc') //正确
// names2.push(123) // 报错
const user: {
name: string,
age: number,
} = {
name: 'zzy',
age: 18,
}
二、TypeScript的数据类型
1.any类型
在某些情况下,我们确实无法确定一个变量的类型,并且可能它会发生一些变化,这个时候我们可以使用any类型。(其实就相当于是回到了普通js)
let msg: any = 'Hello World'
msg = 123
msg = true
msg = {}
console.log(msg)
2.unknow类型
和any类似,不同的是,unknown类型的值上做任何操作都是不合法的
let foo: unknown = 'aaa'
foo = 123
console.log(foo.length) //报错
如果要做相应的操作,必须要先进行类型的校验:
let foo: unknown = 'aaa'
foo = 123
foo = 'bbb'
// console.log(foo.length) //报错
if(typeof foo === 'string') {
console.log(foo.length) //3
}
3.void类型
void通常用来指定一个函数是没有返回值的,那么它的返回值就是void类型,通常用() => void
来指定一个属性是函数类型,比如:
interface Person {
name: string,
coding: () => void
}
1.如果不写void,那么返回什么都不会报错(会有类型的推导的)
function add(num1: number, num2: number) {
console.log(num1 + num2)
return '嗷嗷嗷'
}
let result = add(20,30)
console.log(result) //嗷嗷嗷
2.如果写了void,那么返回值不是undefined,就会报错
function add(num1: number, num2: number): void {
console.log(num1 + num2)
return '嗷嗷嗷' //报错
}
let result = add(20,30)
console.log(result)
3.写void,那么返回undefined是合法的
function add(num1: number, num2: number): void {
console.log(num1 + num2)
return undefined
}
let result = add(20,30)
console.log(result)
4.never类型(了解)
这个类型用的比较少,了解即可
never 表示永远不会发生值的类型,比如一个函数:
如果一个函数中是一个死循环或者抛出一个异常,那么这个函数会返回东西吗?
function foo(): never {
// 死循环
while (true) {}
}
function bar(): never {
throw new Error()
}
不会,那么写void类型或者其他类型作为返回值类型都不合适,我们就可以使用never类型;
5.tuple类型(了解)
元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型
let arr1: any[] = ['zzy', 18, true]
let age = arr1[1] //age的类型是any
let arr2: [string, number, boolean] = ['zzy', 18, true]
let flag = arr2[2] //flag的类型是boolean
比如我们模拟一下react中的useState,明确返回值的类型,可以用到元组。这样可以保证返回的数组中第一个是number,第二个是函数
//模拟react中的useState
function useState(initialValue: number): [number, (newValue: number) => void] {
let stateValue = initialValue
let setValue = (newValue: number) => {
stateValue = newValue
//实现响应式的代码……
}
return [stateValue, setValue]
}
这样可以避免一些奇怪的问题,比如下面如果不声明返回值的类型,那么count当函数用不会报错,这样是不准确的,因为count是一个number类型
function useState(initialValue) {
let stateValue = initialValue
let setValue = (newValue: number) => {
stateValue = newValue
//实现响应式的代码……
}
return [stateValue, setValue]
}
let [count, setCount] = useState(10)
count(123)
三、TypeScript的语法细节
1.可选类型
可以指定某个对象中某个属性是否是可选的(可以不传),语法就是加个问号?
function printPoint(point: { x: number; y: number; z?: number }) {
console.log(point.x)
console.log(point.y)
console.log(point.z)
}
// printPoint({ x: 123}) // 报错,因为y是必传的但没传
printPoint({ x: 123, y: 321 }) // 123 321 undefined
printPoint({ x: 123, y: 321, z: 111 }) // // 123 321 111
2.联合类型
联合类型意思就是可以指定多个类型,表示可以是这些类型中任何一个值:
function printID(id: number | string | boolean) {
......
}
如果我们要做一些操作比如说读取length
,那么就需要对传进来的参数进行类型缩小,不然你怎么知道传进来的是string
还是number
还是boolean
?
function printID(id: number | string) {
if (typeof id === 'string') {
// TypeScript 帮助确定 id 一定是 string 类型
console.log(id.length)
} else {
console.log(id)
}
}
printID(123)
printID('abc')
by the way,其实可选类型本质上可以理解为加上个联合类型undefined
,但是不同是可选类型是可以不传参数的,但是下面这个必须要传参,哪怕传的是undefined
function foo(message?: string) {console.log(message)}
function foo(message: string | undefined) {console.log(message)}
3.类型的别名
使用type
关键字(或interface
,后面讲)来定义类型的别名
type IDtype = string | number
function getId(id: IDtype) {
console.log(id)
}
type pointType = { x: number; y: number; z?: number }
function printPoint(point: pointType) {
console.log(point.x)
console.log(point.y)
console.log(point.z)
}
4.type和interface的区别
- type类型使用范围更广,interface只能用来声明对象
type IDtype = string | number
type pointType = { x: number; y: number; z?: number }
interface pointType { x: number; y: number; z?: number }
- 在声明对象时,interface可以追加声明
interface pointType { x: number; y: number }
interface pointType { z: number }
- interface支持继承,和追加声明效果是一样的
interface IPerson { name: string; age: number }
interface IDantin extends Iperson { habit: string }
const person1: IDantin = {name: 'dantin', age: 18, habit: 'rap'}
5.交叉类型
联合类型表示多个类型中一个即可,交叉类似表示需要满足多个类型的条件;交叉类型使用 &
符号;
interface Person {
name: string
}
interface Behavior {
eat: () => void
}
const me1: Person | Behavior = {
name: 'zzy',
}
const me2: Person & Behavior = {
name: 'zzy',
eat: () => { console.log('吃') }
}
当然上面这些是可以起别名的噢:type IPerson = Person & Behavior
6.类型断言as
有时候TypeScript无法获取具体的类型信息,这个我们需要使用类型断言
//document.getElementById('why')的类型:HTMLImageElement | null
const img = document.getElementById('why') as HTMLImageElement
//这样就不需要类型缩小了
img.src = 'url地址'
当然,这么搞是不行的:
const name: string = 'zzy'
const num:number = name as number
但是这么搞却是可以的(不推荐):
const name:string = 'zzy'
const num:number = name as any as number
7.类型缩小
typeof、instanceof、in、switch-case等
四、函数类型
1.函数调用签名
正常情况下,我们定义一个函数的类型是这样的
//函数调用签名
type BarType = (num: number) => string
const bar: BarType = (num1: number): string => {
return 'zzy'
}
bar(18)
但是,如果我们要描述一个东西可以作为对象被调用,也可以拥有其他属性,就要这样写:
//1.用函数表达式声明类型
//type BarType = (num: number) => string
//2.用函数调用签名
interface IBar {
name: string
age: number
(num: number): string //函数调用签名,用冒号
}
const bar: IBar = (num1: number): string => {
return 'zzy'
}
bar.name = 'zzy'
bar.age = 18
bar(18)
2.参数的可选类型
我们可以指定某个参数不是必传的,可选类型必须写在必传类型的后面
// 可选类型必须写在必须按类型的后面的
// y -> undefined | number
function foo(x: number, y?: number) {
console.log(x, y)
}
foo(20, 30)
foo(20)
这里y的类型是一个联合类型:number | undefined
,也就是说不传的话就是undefined
3.默认参数
// 必传参数 -> 有默认值的参数 -> 可选参数
function foo(x: number, y: number = 100) {
console.log(x, y)
}
foo(20) // 20 100,第二个参数也可以不传,也算个可选参数吧
foo(20, undefined) //这样其实也是对的
4.其他
本部分先占位,细节比较多,暂时没整理完