写在开头
最早接触typescript还是为了应付面试,当时还是在B站上看的尚硅谷的免费教程,看完了就没有然后了。后来进了比较大的公司,老大给我分享了一套typescript教程视频,想着正好借这个机会好好整理一下笔记然后分享出来。这东西网上很多,但是只有自己写的才是自己的,要是能混到路过的大佬指正错误就是真正赚到了。
说回正题,这个系列我会一直写下去,从typescript最基础的内容写到稍微高级一点的应用。但是有些内容我可能不会写太详细,比如类,tsc配置等
官网地址就不贴了,这里贴另外一个我觉得很不错的内容
https://github.com/typescript-cheatsheets/react
用到react的大佬们可以看看
正文
notion地址
https://seasoned-quasar-8c8.notion.site/3eac7a9975254063b989edb7b2a1c31a
为何学习typescript
定义:typescript是JavaScript的超集,需要编译成JavaScript才能在浏览器上运行
优势:
- 能够在开发过程中发现潜在的问题
- 更好的代码提示
- 更好的代码语义,使代码更加易于阅读
基础知识
类型注解和推断:
- 类型注解:type annotation,告知typescript变量类型
- 类型推断:type inference,TS自行推断变量类型
静态类型(同JavaScript,JavaScript是动态类型):
- 基础类型:null,undefined,symbol,boolean,void,number,string
- 对象类型:Object,Array,Function
基础用法
在变量后面添加冒号+类型
函数:
函数还涉及参数的类型,返回值的类型,写法并无太大区别,只是在使用解构时需要注意一下语法规则
const ff = ({num1, num2}: {num1: number, num2: number}) => {
}
返回值的类型需要写在括号之后
const ff = ({num1, num2}: {num1: number, num2: number}): number => {
return 2
}
数组:
注解
数组的注解是小括号 + 中括号,其中小括号类限制数据类型
//数组的内容必须是字符串(括号是可以去掉的,下同理)
const arr: (string)[] = ['a', 'b', 'c']
//数组的内容必须是数字
const arr2: (number)[] = [1, 2, 3]
//数组的内容是字符串或者数字
const arr3: (string | number)[] = ['a', 'b', 1, 2]
需要注意一下多维数组的写法
const arr7: (string | number)[][] = [['a', 1]]
const arr8: (string)[][][] = [[['a']]]
对象类型注解:
//对象类型注解与数组的普通注解原理一致
const arr4: {name: string}[] = [{name: 'a'}]
多数情况下,使用类型别名进行这类的注解是更好的做法
type alias = {name: string, age: number}
const arr5: alias[] = [
{name: 'a', age: 1},
{name: 'b', age: 2},
]
当然,我们也可以使用class进行注解
class Student {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
const arr6: Student[] = [
{name: 'a', age: 1},
new Student('b', 2),
]
从上面的代码可以看出,class的注解并不需要new一个实例,ts会根据class的内容进行约束,在之前的ts版本中,这或许也是一种选择,因为下面这种写法并不会报错
class Student {
name: string;
age: number;
}
但在较新的ts版本中,这种写法并不被推荐
(property) Student.age: number
属性“age”没有初始化表达式,且未在构造函数中明确赋值。ts(2564)
元组
定义:写死的数组
用法:
const tuple1: [string, number] = ['a', 1]
//等号前的代码规定了元组的长度,以及每一个位置的数据类型
对象新增关联用法
接口:
接口是TS中为了方便程序员而增加的一个工具,在TS编译成JavaScript后并不会有接口的代码痕迹
特性同其它编程语言中的接口基本一致,具有implements(实现),extends(继承)
interface Person {
name: string,
}
type Person2 = {
name: string,
}
const f1 = (person: Person) => {
console.log(person.name)
}
const f2 = (person: Person2) => {
console.log(person.name)
}
接口与类型别名的作用非常相似
interface Person3 = string //报错
type Person4 = string
区别在于,type能够直接代表基本类型,但是interface并不支持,需要在后面写一个对象
一般的建议是能写接口就尽量写接口,接口无法满足需要时再用类型别名
接口可选属性:
interface Person5 {
name: string;
age?: number;
}
当一个对象的某个属性并不是必要的时候,这时候我们需要将其标记为可选属性。写法是在冒号前面添加一个问号,这样TS会判定该属性在该类型对象中是可有可无的
只读属性:
interface Person6 {
name: string;
readonly age: number;
}
person.age = 12
(property) Person6.age: any
无法分配到 "age" ,因为它是只读属性。ts(2540)
在属性前面添加readonly,可以将其标记为只读属性,即不允许进行更改
只读属性可以与可选属性进行搭配
interface Person6 {
name: string;
readonly age?: number;
}
未知属性:
interface Person7 {
name: string;
[PropName: string]: any;
}
const person2: Person7 = {
name: 'John',
age: 36,
gender: 'male',
}
当对象有不确定的属性的时候可以使用上面的写法,自带可选特性,也就意味着不能和?一起使用,但是可以和readonly搭配,使用场景较少
interface Person7 {
name: string;
readonly [PropName: string]: any;
}
const person2: Person7 = {
name: 'John',
age: 36,
gender: 'male',
}
person2.name = 'Tom';
person2.age = 23
const person2: Person7
类型“Person7”中的索引签名仅允许读取。ts(2542)
方法属性:
interface Person8 {
name: string;
age: number;
addAge: () => number;
delName(): void;
}
或者纯定义函数
interface SaiHi {
(word: string): void;
}
const say: SaiHi = () => {
}
其它:
在传递对象时,会遇到下面的情况
const person3 = {
name: 'Tom',
age: 23,
gender: 'male',
addAge: () => 2,
delName: () => console.log('hello world')
}
const f3 = (person: Person8) => {
console.log(person.name)
}
f3(person3)
在Person8中,并没有gender属性,但是上面的写法并不会报错
但是如果将写法改成下面这样时就会报错
f3({
name: 'Tom',
age: 23,
gender: 'male',
addAge: () => 2,
delName: () => console.log('hello world')
})
类型“{ name: string; age: number; gender: string; addAge: () => number; delName: () => void; }”的参数不能赋给类型“Person8”的参数。
对象文字可以只指定已知属性,并且“gender”不在类型“Person8”中。ts(2345)
因为通过字面量传递对象会触发TS的强校验
类:
private,protected,public特性与其它编程语言基本一致
类中的属性也支持添加readonly关键字
public,private,protected:
在类构造函数前添加这三个关键字时,相当于在类中声明了该属性,并且进行了初始化
class Person {
constructor(public name: string) {}
}
const person = new Person('tom')
console.log(person.name)
//相当于
class Person {
name: string
constructor(name: string) {
this.name = name
}
}
const person = new Person('tom')
console.log(person.name)
Getter,Setter:
类的getter和setter,可以用来获取类是私有属性或者赋值,它们的使用方法和一个普通的属性一致
class People {
constructor(private _name: string) {}
get name() { return this._name}
set name(value: string) {
this._name = value
}
}
const people = new People('Tom')
console.log(people.name)
people.name = 'Jhon'
console.log(people.name)
单例实现:
class Demo {
private static instance: Demo
private constructor() {}
static getInstance() {
if(!this.instance) {
this.instance = new Demo()
}
return this.instance
}
}
const demo1 = Demo.getInstance()
const demo2 = Demo.getInstance()
console.log('demo2 === demo1: ', demo1 === demo2);
其它:
抽象类
类的知识基本一笔带过了,下一章会写个爬虫的实例,其实已经写完了,等我把第三章肝完了再放出来φ(゜▽゜*)♪