点赞收藏加关注,你也能住大别墅!
我认为JavaScript的特点就是在于它强大的延展性,不仅蔓延到了后端,而且也逐渐成为代码世界无法被忽视的存在。那么,编写js代码时我们都会经常遇到数据类型无法锁定,或者即使锁定也需要编写冗长的判断逻辑,例如:函数参数的类型规范(这里就不展开了)。TypeScript的诞生就解决了这个问题,我称之为js的补完计划。当然,最终ts会被编译为js,但是用ts进行开发,你会体验到一种安心和踏实的感觉,温馨的提示会恰到好处地出现在你需要它的地方。
// 一、ts的静态类型
const year: number = 2013
//Point类中的静态类型约束了变量point的定义
interface Point {
x: number
y: number
}
const point: Point = {
x: 3,
y: 4,
}
//Point2类中的静态类型约束了变量point2的定义
interface Point2 {
x: 1
y: 2
}
const point2 = {
x: 'yi',
y: 'er',
}
// -----------------------------------------------------
// 二、类型注解、类型推断
//1.注解
let count: number
count = 123
//2.推断
let count2 = 123
// -----------------------------------------------------
// 三、ts中的基础类型,对象类型
// 1.基础 :number, string, boolean, null, undefined, symbol, void
// 2.对象:Object, [], function, 类
// (1)一般函数
// function add(形参1:number,形参2:number,...):返回值类型number等 {
// return num1+num2;
// }
function add(num1: number, num2: number): number {
return num1 + num2
}
// (2)无返回值函数
function testVoid(): void {
console.log('没有返回值')
}
// (3)never
function haha(): never {
while (true) {}
}
// (4)解构
function jiegou({ num1, num2 }: { num1: number; num2: number }): number {
return num1 + num2
}
const res = jiegou({ num1: 1, num2: 2 })
// (5)箭头函数
const func = (str: string): string => {
return str
}
// ---------------------------------------------------------------
// (6)数组
const arr: number[] = [1, 2, 3]
const mixarr: (number | string)[] = [1, '2', 3]
const objarr: { name: string }[] = [{ name: 'ts' }]
// 类型别名
type User = { name: string }
const objarr2: User[] = [{ name: 'ts' }]
class User3 {
name: string
age: number
}
const objarr3: User3[] = [{ name: 'ts', age: 9 }]
// ---------------------------------------------------------------
// (7)元组
// 当需要按固定长度、固定数据类型来约束数组中数据类型的时候需要使用元组
const useInfo: [string, number] = ['ts', 9]
// csv
const csvarr: [string, number][] = [
['js', 9],
['ts', 10],
]
// (8)json
interface Person {
name: string
}
const jsonstr = '{"name":"ts"}'
const newname: Person = JSON.parse(jsonstr)
//(9)类型不确定
let msg: number | string = 123
msg = '123'
//接口interface
interface Person {
// readonly stname:string; readonly 表示不能修改这个属性,只可以读取属性值
stname: string
age?: number // ?表示age属性可有可无
//[propName:string]:any 当实例中可能含有未约束的属性时,可以增加这样一行代码
say(): string
}
const getPersonName = (person: Person): void => {
console.log(person.stname)
}
const setPersonName = (person: Person, stname: string): void => {
person.stname = stname
}
const person = {
stname: 'js',
sex: 1,
say() {
return 'hello'
},
}
getPersonName(person)
// getPersonName({
// stname: 'js',
// sex:1
// })------------------------直接传字面量会触发ts的强校验,所以这样写会报错,可以在类中定义[propName:string]:any来解决
setPersonName(person, 'ts')
// ---------------------------------------------------
// 类 class
class User implements Person {
stname = 'dell'
say() {
return 'hellp'
}
}
// 继承
interface Teacher extends Person {
teach(): string
}
const person2 = {
stname: 'js',
sex: 1,
say() {
return 'hello'
},
// 父接口中并未定义teach(),但是,子接口中定义了,那么这个数据不仅要符合父接口,也要符合子接口
teach() {
return 'teach'
},
}
//继承的接口 = 子 + 父 中定义的属性和方法
const getPersonName2 = (person: Teacher): void => {
console.log(person.stname)
}
getPersonName2(person2)
//--------------------------------------------
// 接口定义函数
interface Fun {
(msg: string): string
}
const tsfun: Fun = (msg) => {
return 'this is Fun'
}
// 类的定义和继承
class Star {
name = 'star'
getName() {
return this.name
}
}
class Moon extends Star {
getMoonName() {
return 'moon'
}
}
const star = new Star()
const moon = new Moon()
console.log(star.getName())
console.log(moon.getMoonName())
// 重写
class Mars extends Star {
//重写了父类的getName方法
getName() {
return 'Mars'
}
}
// 字类中调用父类中的属性或者方法
class Jupiter extends Star {
//重写了父类的getName方法
getName() {
return super.getName() //此时调用的是父类中的getname方法
}
}
// 访问类型 public private protected
// 1.public 类的内部和外部均可调用
class Car {
public name: string
public getName() {
this.name // ----内部可以使用
}
}
const car = new Car()
car.name = 'tesla'
// 2.private 类的内部使用
class Car2 {
private name: string
public getName() {
this.name // ----内部可以使用
}
}
const car2 = new Car2()
//car2.name = 'tesla' ---- 外部使用会报错
class Tesla extends Car2 {
public getName() {
//super.name ---- 子类中也不可以使用
}
}
// 3.protected 类的内部及继承的字类中使用
class Car3 {
protected name: string
public getName() {
this.name // ----内部可以使用
}
}
class Byd extends Car3 {
public getName() {
super.name // 子类中可以使用
}
}
const car3 = new Car3()
//car3.name = '' ---- 外部使用会报错
// 构造器 constructor 简化了属性的定义和赋值
class Car4 {
//public name:string
//constructor(name: string) {
//this.name = name
//}
//简化
constructor(public name: string) {}
}
const qq = new Car4('qq')
console.log(qq.name)
//子类构造器中必须调用父类中的构造器,super()
class Car5 {
constructor(public name: string) {}
}
class Yd extends Car5 {
constructor(public age: number) {
super('car')
}
}
// get set
class Food {
constructor(private _name: string) {}
get name() {
//处理代码
return this._name
}
set name(name: string) {
//处理代码
this._name = name
}
}
const food = new Food('apple')
//food.name = "orange" ---- 私有属性无法外不适用,所以需要使用get、set
food.name = 'orange'
console.log(food.name)
// 单例模式
class OnlyOne {
private static instance: OnlyOne
private constructor() {}
static getInstance() {
if (!this.instance) {
this.instance = new OnlyOne()
}
return this.instance
}
}
const obj1 = OnlyOne.getInstance()
const obj2 = OnlyOne.getInstance()
//无论创建多少实例,都只是同一个对象
//抽象类 可以把它理解成一个公共类,可以把多个类中都有的方法、属性存在抽象类里,由各个类继承抽象类
abstract class MoonPerson {
abstract name: string
abstract say(): string
}
// const p = new Person() ---- 抽象类不可以实例化
// 子类中必须实现抽象类中的抽象方法、属性
class Man extends MoonPerson {
name: 'tom'
sex: 1
say() {
return 'haha'
}
}
class Woman {
name: 'jane'
sex: 0
say() {
return 'xixi'
}
}
//interface也可以用类似抽象类的方式,把多个接口中都有的东西,存在一个接口中,多个接口可以通过继承的方式获取都有的东西,从而简化代码
interface Man {
name: string
sex: 1
huzi: true
}
interface Woman {
name: string
sex: 0
dress: true
}
function test(person: Man | Woman) {
//console.log(person.dress) ---- 联合类型中只能使用两个类型中都有的属性或者方法 ---- 类型保护可以解决这个问题
}
//类型保护1: 接口中定义了区分不同类型的标记,通过判断标记来判断类型,这也叫做类型断言
function test2(person: Man | Woman) {
if (person.sex) {
;(person as Man).huzi
} else {
;(person as Woman).dress
}
}
//类型保护2:in 语法
function test3(person: Man | Woman) {
if ('huzi' in person) {
;(person as Man).huzi
} else {
;(person as Woman).dress
}
}
//类型保护3:typeof 语法
function test4(num1: string | number, num2: string | number) {
if (typeof num1 === 'string' || typeof num2 === 'string') {
return `${num1}${num2}`
} else {
return num1 + num2
}
}
//枚举类型 ----- 适用于有固定值的数据
enum Status {
OFFLINE,
ONLINE,
DELETED,
}
function getStatus(status) {
if (status === Status.OFFLINE) {
return 'offline'
} else if (status === Status.ONLINE) {
return 'online'
} else if (status === Status.DELETED) {
return 'deleted'
} else {
return 'error'
}
}
const res = getStatus(Status.OFFLINE) // ---- 结果为offline2
const res2 = getStatus(0) // ---- 结果为offline2
console.log(res)
console.log(res2)
//泛型 ---- 数据类型在定义时不确定,在实现时再确定
function fun1<T, P>(first: T, second: P) {
return `${first}${second}`
}
function fun2<F>(params: Array<F>) {
return params
}
fun1<number, string>(1, '1') // 也可以写成fun1(1,'2')
fun2<string>(['123'])
//泛型的继承
class DataFucker<T extends number | string> {
constructor(private data: T[]) {}
getItem(index: number): T {
return this.data[index]
}
}
const arr = new DataFucker<number>([])
const arr2 = new DataFucker<string | number>([])
const arr3 = new DataFucker<string>([])
//泛型作为一个具体的类型注解
function hello<C>(params: C) {
return params
}
//命名空间 ---- 可以理解成模块
//在命名空间中的东西,如果没有通过export 向外界暴露,那么外界是无法直接获取命名空间里的东西的。
namespace Zoo {
class HaveDog {
name: string
}
class HaveCat {
name: string
}
export class People {
constructor() {
new HaveDog()
new HaveCat()
}
}
}
//无法直接获取
//const dog = new HaveDog()
//const cat = new Zoo.HaveDog()
//但是可以通过暴露出来的People来获取
const p = new Zoo.People()
//当然,命名空间也是可以相互引用的,需要在当前文件中加上: