TypeScript 学习笔记

数据类型

TypeScript包含的数据类型:

  1. boolean 布尔类型
  2. number 数值类型
  3. string 字符串类型
  4. array 数组类型
  5. void 空类型
  6. undefined
  7. any 任意类型
  8. null 空类型
  9. NaN 非数值
  10. enum 枚举类型
  11. tuple 元组类型
  12. unknown 不可预先定义的类型
  13. never 永远不知道什么类型

基本写法

let a: boolean = false;
let b: number = 1;
let c: string = 'c';
let g: any = 1;
	g = '1212';
	g = false;
	g = undefined;
	g = null;

//数组
let arr1: Array<string> = ['','']
let arr2: Array<string|number> = ['a',1,'A']
let arr3: number[] = [1,2]
let arr4: (string|number)[] = [2,'B','b']

//元组类型
let f: [string,number] = ['hello', 5];	

//枚举类型
enum Gender{
    BOY,
    GIRL
}
let g1: Gender = Gender.BOY;
let g2: Gender = Gender.GIRL;
console.log(Gender); //{0: 'BOY', 1: 'GIRL', BOY: 0, GIRL: 1}
console.log(g1); //0
console.log(g2); //1

const enum Color {
    RED=1,
    YELLOW,
    BLUE,
}
console.log(Color.RED,Color.YELLOW,Color.BLUE); //1 2 3

联合类型

let x: number|string|boolean|null|undefined;
	x = 1;
	x = null;
	x = undefined;

void类型

  • void类型表示没有任何类型
function A(): void {
	return undefined
}

never类型

  • never 是指没法正常结束返回的类型,一个必定会报错或者死循环的函数会返回这样的类型。
//一个函数永远不会返回,那么他的返回值类型就是never
function fun(): never{
	 while(true){
		console.log('哈哈')
	 }
}
//如果函数一定要抛出错误,那么他也永远不会正常结束,他的返回类型也是never
function fun():never{
	throw Error('错误');
}

类型断言

  • 强行告诉ts我是什么类型。类型断言好比其它语言里的类型转换,但是它不进行特殊的数据检查和解构。
// 第一种写法:尖括号<>写法
let h: any = 'abc'
let h_len: number = (<string>h).length;
console.log(h_len)	// 3
// 第二种写法:as写法
let h: string|number|boolean;
h = 'git'
console.log((h as string).length)

在TypeScript里使用JSX时,只有 as语法断言是被允许的。

函数

函数定义

function fun2 (str: string): string {
	return `${str},你好`
}
fun2('JIKA')

函数表达式

// 定义一个类型来约束函数表达式
type FunRestrain = (x: string,y: string) => string;	//此处不是箭头函数,只是用来分割
// 必须传入类型约束的参数类型、参数个数,返回参数类型,否则报错
let createName: FunRestrain = (firstName: string, lastName: string): string =>{
    return firstName+lastName;
}
createName('张','三')

函数重载

let obj: any = {};
function attr (val: string): void;
function attr (val: number): void;
//function attr(val: string | number) :void; 这种写法和上面两行的效果相同
function attr (val: any): void{
	if(typeof val == 'string'){
		obj.name = val
	} else if (typeof val == 'number'){
		obj.age = val
	}
}
attr('linjun')
attr(10)
// attr(true)  //报错,没有与此调用匹配的重载。

函数的其他补充

可选参数 ?

function mFun (x?: string) {
	console.log(x)
}
mFun('Q')   //Q
mFun()  //undefined

默认参数

function mFun (x: string = 'K') {
	console.log(x)
}
mFun('Q')   // Q
mFun()  // K
  • 注意:不能同时使用 可选参数和默认参数

剩余参数

function fun1(...params: number[]) {
	console.log(params)
}
fun1(1,2,3,5) // [1, 2, 3, 5]


function fun2(...params: Array<string|number>) {
	console.log(params)
}
fun2(1,2,3,'AA',5) // [1, 2, 'AA', 5]

//若要传入其他参数,则剩余参数必须放在最后
function sum(str: string, ...params: (number|string)[]) {
	console.log(params)
	params.push(str)
	console.log(params)
}
sum('看看',1,2,3,'AA',5)     //[1, 2, 3, 'AA', 5]
                            //[1, 2, 3, 'AA', 5, '看看']

基本应用

class Cat {
	color: string;
	constructor (color: string) {
		this.color = color
	}
	getColor (): void {
		console.log(this.color)
	}
}

let a_cat = new Cat('orange')
console.log(a_cat)

运行结果:

class Animal {
    color: string;
    size: string;
    constructor (color: string, size?: string) {
        this.color = color
        this.size = size
    }
    get colour () {
        return this.color
    }
    set colour (param: string) {
        this.color = param
    }
    get shape () {
        return this.size
    }
    set shape (param: string) {
        this.size = param
    }
}

let cat = new Animal('orange')
console.log(cat.color, cat.size)  // orange undefined
cat.color = 'white'
cat.size = 'large'
console.log(cat.color, cat.size)  // white large
console.log(cat.shape()) //报错。get和set访问器不能被外部调用

类的继承 extends

  • 继承可以描述类与类之间的关系。比如:A和B都是类,B是A,那么A和B形成继承关系,我们把A叫做父类B叫做子类。

类的重写

子类可以重写父类的属性和方法,但是不能改变父类其类型,类型必须匹配。

  • 子类重写父类的属性
class People {
    eyes: number = 2;
    body: boolean = true;
}

class Boy extends People{
    eyes: number = 1;   // Boy类从People类继承的eyes属性的值被改变
    // body: string = '存在';   // 报错:不能将类型“string”分配给类型“boolean”。
    hand: string = '2只手';   // Boy类的自有属性
}

let kid = new Boy();
console.log(kid.eyes)   // 1    
console.log(kid.hand)   // 2只手
  • 子类重写父类的方法
classPeople {
    getFeature () {
        console.log('我是人类')
    }
    otherFeature () {
        console.log('我需要学习')
    }
}

class Boy extends People{
    getFeature () {
        console.log('我是个小朋友')
    }
}

let kid = new Boy();
kid.getFeature()    // 我是个小朋友
kid.otherFeature()  // 我需要学习

this关键字

  • 在继承关系中,this的指向是动态的,根据调用者来确定this指向。
class Person {
    name: string = '一个人';
    sayHello () {
        console.log(`你好,我是${ this.name }`)
    }
}
class Man extends Person {
    name: string = '罗森';
    sayHello () {
        console.log(`你好,我是${ this.name }`)
    }
}
let m = new Man()
m.sayHello()	//这里是m调用的,它指向Man这个类,所以输出 “你好,我是罗森”

super关键字

  • 当我们在子类中调用父类的方法时,可以使用super关键字
class Person {
    name: string = '';
    sayHello () {
        console.log(`你好,我叫${ this.name }`)
    }
}
class Student extends Person {
    name: string = '豆豆';
    exp () {
        super.sayHello()    //你好,我叫豆豆。
        this.sayHello()     //你好,我叫豆豆。
    }
}
let h = new Student()
h.exp()

在子类没有重写父类方法的前提下,使用super调用父类的方法时,superthis的效果相同。

但是,如果子类重写了父类的方法,则superthis的效果会有差异。

class Person {
   name: string = '';
   sayHello () {
       console.log(`你好,我叫${ this.name }`)
   }
}
class Student extends Person {
   name: string = '豆豆';
   // 重写父类的方法
   sayHello () {
       console.log(`${ this.name },很高兴遇见你!`)
   }
   exp () {
       super.sayHello()    //你好,我叫豆豆。
       this.sayHello()     //豆豆,很高兴遇见你!
   }
}
let h = new Student()
h.exp()

抽象类 abstract

  • JS中没有抽象类,它是TS中提出来的。有时候,某个类只表示抽象的概念,主要用于提取子类共有的成员,而不是直接创建它的实例,这时该类可以作为抽象类。只要给类前面加上abstract,就可以表示抽象类,抽象类不可以创建实例
  1. 抽象类和其他类区别不大,只是不能被实例化
  2. 抽象类是专门用来被继承的类,抽象类中可以添加抽象方法,抽象方法以abstract开头,没有方法体。
  3. 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写。
  4. 接口里的方法都是抽象的。

抽象父类

abstract class People {}
class man extends People {}
class woman extends People {}
// let P = new People()    //报错:无法创建抽象类的实例。
let m = new man()
let w = new woman()

抽象成员

  • 在父类中,可能只知道某些成员是必须存在的,就像人都有名字,但在父类中没办法直接书写具体的名字,只能在子类中知道,因此,需要一种强约束,让继承父类的子类必须实现该成员。

注意:只有在抽象类中才能使用抽象成员

abstract class Person { //抽象类
    abstract readonly name: string  //抽象成员
}
//子类实现抽象成员,第一种方式
class boy extends Person {
    readonly name: string = '凯凯'
}
//子类实现抽象成员,第二种方式
class girl extends Person {
    readonly name: string;
    constructor () {
        super()		//派生类的构造函数必须包含 "super" 调用。访问派生类的构造函数中的 "this" 前,必须调用 "super"。
        this.name = '娜丽'
    }
}
//子类实现抽象成员,第三种方式
//这里没有写 set 访问器,所以本身就是只读的,所以可以不用 readonly,也没法用
class baby extends Person {
    get name (): string {
        return '小夏'
    }
}
const b = new boy()
const g = new girl()
const bb = new baby()
console.log(b.name, g.name, bb.name)    //凯凯 娜丽 小夏

静态成员 static

  • 静态成员就是附着在类上的成员,包括属性和方法。如果在JS当中,我们可以说附着在构造函数上的成员。使用static修饰的成员称作静态成员,静态成员也称作非实例成员,它是属于某个类的,而实例成员也叫对象成员,它是属于某个类的对象。
  • 当类中的方法被声明为static时,其 实例化对象不可调用该方法只有 类 本身 ,以及 子类 可以调用
  • 静态方法中的this指向当前类,而实例方法中的this指向当前对象
class Person {
    name_1: string = '哈哈';
    static gender: string = '女';
    static sayHello () {
        // console.log(this.name_1)  // undefined  类型“typeof Person”上不存在属性“name_1”。
        console.log(this.gender)     // 女 在静态方法中,取到当前所在类的静态变量
        this.gender = '男';
        console.log(this.gender)   // 男
        console.log(this.name)   // Person    该class的名称
        console.log(this)   //Person类	class Person { ... }
    }
}
Person.sayHello()
let p = new Person()
console.log(p.name_1)    //哈哈
// p.sayHello()    //Uncaught TypeError: p.sayHello is not a function

继承类的情况:

class Person {
    name_1: string = '哈哈';
    static gender: string = '女';
    static sayHello () {
        // console.log(this.name_1)  // undefined  类型“typeof Person”上不存在属性“name_1”。
        console.log(this.gender)     // 女 在静态方法中,取到当前所在类的静态变量
        this.gender = '男';
        console.log(this.gender)   // 男
        console.log(this.name)   // Men    该class的名称
        console.log(this)   //Men类   class Men extends Person { ... }
    }
}

interface sleep {	//接口里的方法都是抽象的
   time():void;
}

class Men extends Person {
    sayHello () {
        console.log('我是Men的方法')
    }
}

let m = new Men()
console.log(m.name_1)   //哈哈
m.sayHello()   //我是Men的方法
Men.sayHello()

Men.sayHello() 调用的是Men内自定义的sayHello()方法,和Person中的sayHello()方法相互独立,互不影响。

其他修饰符

通过类型的继承来讲一下访问修饰符 public protected private

public

  • 修饰属性和方法,里里外外都能访问,自己、自己的子类、其他类都能访问
  • 不写修饰符,默认就是 public

protected

  • 受保护的,类内部以及其子类内部非 static 方法内可访问,实例化对象和子类也不可访问
class Person {
    name: string = '';
    age: number = 0;
    protected eat () {
        console.log('吃饭')
    };
    eat2 () {
        this.eat()
        console.log('吃水果')
    }
}

let p = new Person()
p.eat2()    //吃饭   吃水果
// p.eat()     //属性“eat”受保护,只能在类“Person”及其子类中访问。
// Person.eat()    //Uncaught (in promise) TypeError: Person.eat is not a function
class Person {
    name: string = '';
    age: number = 0;
    protected eat () {
        console.log('吃饭')
    };
}

class Boy extends Person {
    boy1 () {
        this.eat()
    }
    private boy2 () {
        this.eat()
    }
    protected boy3 () {
        this.eat()
    }
    static boy4 () {
        // this.eat()  //类型“typeof Boy”上不存在属性“eat”。
    }
}

let b = new Boy()
b.boy1()    // 吃饭
// b.boy2()    //属性“boy2”为私有属性,只能在类“Boy”中访问。
// b.boy3()    //属性“boy3”受保护,只能在类“Boy”及其子类中访问。
// b.eat()     //属性“eat”受保护,只能在类“Person”及其子类中访问。
// Boy.eat()   //类型“typeof Boy”上不存在属性“eat”。

private

  • 私有的,只能在本类内部使用,实例化对象和子类都不能访问
class Person {
    name: string = '';
    age: number = 0;
    private eat () {
        console.log('吃饭')
    };
    eat2 () {
        this.eat()
        console.log('吃水果')
    }
}

let p = new Person()
p.eat2()	// 吃饭   吃水果
// p.eat()     //属性“eat”为私有属性,只能在类“Person”中访问。
// Person.eat()    //Uncaught (in promise) TypeError: Person.eat is not a function

接口

用来表示对象的形状

interface Student {
    name:string,
    study():void,
    eat?():void,

}

let s:Student = {
    name: 'Star',
    study () {
        console.log('十点睡觉')
    },
    // sleep () {}     //报错      “sleep”不在类型“Student”中。
}

用来描述行为的抽象

interface People {
    name:string,
    study():void,
    eat():void,
}

interface Man extends People {
    sleep(): string,
}

//implements 实现,一个新的类,从父类或者接口实现所有的属性和方法,同时可以重写属性和方法,包含一些新的功能
class Kid implements Man {
    name:string;
    study() {};
    eat() {};
    sleep() {
        return '睡觉'
    };
    age: number;  //Kid类自定义属性
    jump () {   //Kid类自己的方法
        console.log('跳远')
    }
}

//extends 继承,一个新的接口或者类,从父类或者接口继承所有的属性和方法,不可以重写属性,但可以重写方法,可以包含一些新的功能
class Boy extends Kid {
    // age: string;    //报错  不可以重写Kid类中的属性
    jump () {   //可以重写Kid类中的方法
        console.log('重写Kid类中的jump')
    };
    drink () {
        console.log('自定义方法')
    }
}

补充

  1. 接口 不能实现 接口或者类,所以实现只能用于类身上,即类可以实现接口或类
  2. 接口 可以继承 接口或者类
  3. 类不可以继承接口,类只能继承类
  4. 可多继承或者多实现

接口类型的 必要属性 和 可选属性

interface Animal {
    readonly id: number,	//必要属性
    name: string,			//必要属性
    [otherProp: string]: any	//任意属性
}

let cat:Animal = {
    id: 1,
    name: 'Kitty',

    age: 2,
    sex: 'female'
}

用接口规范、定义函数

interface SalePricefun {
    (price:number): number
}
let goods:SalePricefun = (price:number):number => {
    return price*1.08
}

interface WeekFun {
    (): number
}
let order:WeekFun = () => {
    return Math.round(Math.random()*10)
}

// 接口定义函数的入参类型
interface RulesFun {
    (...args: any[]):number
}
let other:RulesFun = (...params:number[]):number => {
    console.log(params)
    return params.reduce((pre,cur) => pre+cur)
}
other(3,'1',2)  //调用函数时,在RulesFun接口定义的入参为any类型的条件下,不受other函数规定的入参类型限制
        

可索引接口,对数组或对象进行约束

// 索引为number类型
interface Arr {
    [index: number]: string
}

let n:Arr = ['w','e']
console.log(n)      //['w', 'e']


// 索引为string类型
interface Obj {
    [index: string]: string
}

let o = {
    'a': 1,
    'b': 2
}
console.log(o)      //{a: 1, b: 2}

类的接口,用接口约束构造函数的类型

class Animal{
    constructor(public name:string, public age: number){}
}
interface WithNameClass{
    new(name:string, age: number): Animal; //类的构造函数是接口的属性
}
function createClass(clazz:WithNameClass, name:string, age: number){
    return new clazz(name, age);
}
let a4 = createClass(Animal, 'zhufeng', 18);
console.log(a4);    // Animal {name: 'zhufeng', age: 18}

泛型

  • 泛型(Generics):在定义函数、接口或者类的时候不预先指定具体的类型,等到使用时再指定具体类型的一种特征。
type A = string | number;   //等同于  type A = '' | 1;   定义A支持string和number类型 
// let a:A = false //报错:不能将类型“boolean”分配给类型“A”。
let a:A = '哈哈'
let aa:A = 123

type F<T> = T | T[]
type FString = F<string>
type FNumber = F<number>

type Add<K> = (a: K, b: K) => K
// type AddNumber = Add<number>
const AddN: Add<number> = (a,b) => a+b
const AddS: Add<string> = (a,b) => a+''+b

泛型函数

function fun<T> (prop: T): T {		// <T>为类型占位符,通过链式传递给参数类型和返回值类型
   return prop
}

let a = fun('字符串')
let b = fun(false)
let c = fun([1,'1'])
let d = fun(1)
let e = fun(undefined)
let f = fun(null)
let g = fun(NaN)

泛型接口

interface Cal {
    <T>(a: T): T
}

let add: Cal = (a) => {
    return a
}
console.log(add('哈哈'))
console.log(add<string>('哈哈'))

//在定义接口的时候也可以指定泛型
interface Cart<T> {
    list: T[]
}
let c:Cart<number> = {list: [1,2,3]}

// type可以定义泛型的别名
type Cart2<T> = {list: T[]} | T[]
let c2:Cart2<number> = {list: [3,4]}
let c3:Cart2<number> = [6,7]

泛型类

  • 在类名后面跟上类型变量,就能够在类中应用这些泛型类型。
class Person<T, V> {
    name: T;
    getAge: (age: V) => V
}
let p = new Person<string,number>();
p.name = 'Jake';
p.getAge = (x) =>  x;
p.getAge(23)

泛型继承(约束泛型)

interface Len {
    length: number,
}
function arr<T extends Len> (val: T) {
    console.log(val.length)
}
arr([1,2,3])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值