typeScript学习

typescript

元组

let arr: [string,number] = ['haha',3]

enmu类型

enum Color {
  Red = 3,
  Blue,
  Green
}
let color = Color[0]
console.log(color) // undefined

let color2 = Color[3]
console.log(color2) //red

可以指定序号

enum Color {
  Red = 3,
  Blue = 5,
  Green = 7
}

any类型

void类型

没有返回值

function test ():void {
	console.log("void")
}

undefinednull

undefinednull 的子类型,所以可以赋值给它

let u: null = null
let n: null= undefined

never类型

它是任何类型的子类型,=

Object 类型

类型推断和类型断言

let someValue: any = "hello world" // 此处就是类型断言
// let length: number = (<string>someValue).length // 强制转化

let someLength: number = (someValue as string).length //类型推断
console.log(someLength)

变量声明

解构

  • 剩余参数

  • 对象

    let o = {
    	a: 'haha',
    	b: 22
    }
    
    let {a: newName1, b:newName2} = o
    // ==>
    let newName1 = o.a 
    let newName2 = o.b
    //ts 
    let {a,b}: {a: string, b:number}  = o
    
    function f({a,b = '3'} = {a = ''}):void {}
    f()
    f({}) 可以不传第一个数组,但是如果传了必须就有值
    
  • 数组

展开

  • 数组

    let arr = [3,4,5]
    let arr2 = [7,8,9]
    let arr3 = [...arr,...arr2]
    console.log(arr3)
    
  • 对象

    let obj = {
    	name: 'kangkang',
    	age: 32
    }
    
    let obj2 = {...obj,class: 'four'}
    console.log(obj2)
    

    同名属性后面的值会覆盖前面的值!!!

接口

//定义接口使用interface 需要定义接口的名字,接口不在意属性的顺序,只在意属性名和值得类型
interface LabelValue {
  label: string
}

function printLabel (labelObject: LabelValue) {
  console.log(labelObject.label)
}

let obj = {name: 'kangkang', label: 'string'}

printLabel(obj) // 传进去的对象包含被检测属性

可选属性and只读属性

可选属性必须在必须属性后面,且可选属性时可选的

interface value {
	x?: number,
	y?: string
}

一些属性只在定义时需要改变可以选用只读属性

interface value {
	readonly x: number,
	readonly y: string
}

额外的属性检查和函数类型和可索引的类型

typeScript会对对象自变量做额外的变量检查,如何避开?

interface values {
  x?: string,
  y?: number
}

// let testValues: values = {xx: 'haah',x: 'haha',y: 333}

let a = { xx: 'haah', x: 'haha', y: 333 }
let testValues: values = a

或者

interface values {
  x?: string
  y?: number
  [popsName: string]: any
}

let a = { xx: 'haah', x: 'haha', y: 333 }

类类型和继承接口+ 混合类型+ 接口继承类型

class Clock implements Clock {
  constructore(x: number, y: number) {

  }
  currentTime:Date
  newTime(d: time) {
    this.currentTime = d
  }
}

什么时候该用静态接口什么时候该用动态接口?

静态类类型

interface ClockConstructor {
  new (x: number, y: numebr): Clock
}

构造器里的类型需要通过静态类型来对其进行检查,如上.

继承接口(单继承和多继承)
interface Father { 
  color: string
}
interface Mother {
  phone: number
}
interface Son extends Father,Mother{
  age: string
}
let person = {} as Son
person.color = 'red'
person.age = '12'
person.phone = 32

console.log(person)

混合类型

interface Counter {
  (x:number): number
  interel: string
  reset() :void
}

function getValue(): Counter {
  let counter = (function(x: number ) {
    return x
  }) as Counter

  counter.interel = '32'
  counter.reset = function() {console.log('haha')}

  return counter
}

getValue().reset()
接口继承类

当一个接口继承一个类的类型时,会继承它的一些私有成员什么的,所以当接口继承类后,创建新类使用接口后如果新类没有继承原类直接指定此接口会导致一些私有属性等没有成功被继承,从而报错

class orset  {
  private state: any
}

interface orsets extends orset {
  reset(): void
}

class test extends orset impelments orset{
  reset(): void{
    console.log("rest implement")
  }
}
// 未继承orset类,缺少私有属性state
// class  test2  implements orset {
//   reset() {
//     console.log("error")
//   }
// }

类 继承

class person {
  name: string
  constructor(name: string) {this.name = name}
  sayName(a:string):void {
    console.log(this.name  + a)
  }
}

class mary extends person {
  constructor(name: string) {
    console.log("构造函数执行...")
    // 调用父类构造函数
    super(name);
  }
  sayName(a: string = "你好"): void {
    console.log("mary ...");
    // 调用父类方法
    super.sayName(a);
  }
}

let test = new mary('mary')
test.sayName()

类公有、私有、受保护的修饰符 + readonly 修饰符

publicprivateprotected

私有成员实例及子类实例子类也不可访问,但是保护成员的子类型可以访问父类

类的静态属性和存取器

let seret = 'acdsdfadfa'
class test {
  private name: string
  // constructor (name: string) {
  //   this.name = name
  // }
  get names() {
    return this.name
  }
  set names(newName: string) {
    if(seret && seret === 'acdsdfdfa') {
      this.name = newName
    }else {
      console.log("它是穿山甲")
    }
  }
}
let newTest = new test()
newTest.names = 'hah'
// 我是穿山甲

静态属性时存在类的本身(可直接通过类来访问它),不是在类的实例上

class instance {
  static origin = { x: 0, y: 0 };
  scale: number;
  constrouctor(scale: number) {
    this.scale = scale;
  }

  calculateRadius(point: { x: number; y: number }) {
    // 直接通过类名去使用它
    let xDist = point.x - instance.origin.x;
    let yDist = point.y - instance.origin.y
    return { xDist, yDist };
  }
}

抽象类

抽象类里面包含抽象方法,抽象方法不能被直接实现需要去派生类中实现

抽象类也不能被实例化

类也可以作为类型

abstract class city {
  city: string
  constructor (city:string) {
    this.city = city
  }
  // 抽象类的方法也需要在派生类中去实现
  abstract sayCity() :void
}
// let x = new city() // 无法创建抽象类的实例
class citys extends city {
  static adr: string = 'kangkang'
  constructor() {
    super('nanjing')
  }
  sayCity():void {
    console.log(this.city)
  }

  sayHello(value:string):void {
    console.log(value)
  }
}

// 此处的citys是实例类型
let x:citys = new citys()
x.sayCity()
x.sayHello('haha')

//  typeof citys是获得citys类 类型
let y: typeof citys = citys
y.adr = 'hehe'

 let z: citys = new y()
 z.sayHello('hwhw')

函数

匿名函数和命名函数

函数类型包含两部分,一部分是参数类型一部分是函数返回类型

let pro:(name: string,age: number) => number = function(x: string,y:number):number { return age++}

可选参数和默认参数

function buildName(firstName: string, lastName? : string ) {
  if(lastName) {
    return firstName + lastName
  }else {
    return firstName
  }
}

let x = buildName('dai')
console.log(x)

可选参数必须在必须参数的后面,而带有默认参数的可选参数可以在前面

剩余参数

function buildName(firstName:string, ...rest: string[]){}

this问题

泛型

为什么需要泛型?泛型如何使用?

比如当你在函数中需要输入和返回的类型统一但是你在未使用前还不确定会是哪种类型的时候

// 此时传入的类型和返回的就不一定会相同了*

function test (x:any) :any {

  return x + ''

}

使用方法

let x1 = test<string>('string')

let x2 = test('string')

当使用了T类型不存在的属性后会报错,我们使用具有此属性比如数组可以


function list <T> (type: T) {
  return type.length //类型T上不存在属性length
}
function list2<T>(type: T[]) {
  return type.length
}

泛型类型

function list2<T>(type: T) {
  return type
}
interface iden <T> {
  (arg:T): T
}
let s: iden<number> = list2

泛型类

将泛型的类型名放在类名的后面可以让里面均可以使用这个类型的变量来定义

class iden<T> {
  name: string
  key: T
  add: (s:T) => T
}

let x = new iden<number>()

x.add = function (s: number) { 
  return s + 2
}

泛型不可以作用于静态属性的

泛型约束

interface types {
  length: number
}

let s = function<T extends types>(s: T) {
  console.log(s.length)
}

s("33")
s(22) // error 22不具有length属性
s({length: 222})

类型约束(k必须是T的属性才行)

function x<T, K extends keyof T>(obj: T, key: K) {
  return obj[key]
}
let obj = {a: 3, b: 4, c: 5}
let s = x(obj,'b') 
let s2 = x(obj,'s') // error 类型s的参数不能赋值给类型 a| b| c的参数
class one {
  name: string
}

class two {
  age: number
}

class profile {
  key: number
}

class a extends profile {
  sayName: one
}

class b extends profile {
  sayAge : two
}

function createFn <T extends profile>(c: new() => T): T {
  return new c()
}
let test = createFn(b).sayAge.age
let test2 = createFn(a).sayName.name

类型推断和最佳通用类型和上下文类型

在声明变量和参数类型以及返回类型的时候会出现类型推断

考虑如下情况

let x = [0,'a',null] // number | string | null 

其中任意类型均可


如下情况


class Mother {}
class Son extends mother{
  name: string 
}
class Daughter  extends mother{
  name: string
}

let s = [new son(), new daughter()] 

当我们s被推断出mother 时上面这种写法并不能实现

let s: Mother = [new son(), new daughter()] 

上下文类型

window.onmousedown = function(event) {
  console.log(event.click)
}
// mouseEvent 上不存在click事件

window.onmousedown = function(event: any) {
  console.log(event.click);
};

第一个会通过左边来推断右边的类型,对于mousedown来说它不存在click事件,而你指定类型就会使得这样的类型推断失效

class Mother {}
class Son extends mother {
  name: string;
}
class Daughter extends mother {
  name: string;
}
// Mother会作为最佳通用类型
function x(): Mother[] {
  return [new Son(), new Daughter()]
}

高级类型

  • 交叉类型

    会将多个类型合并为一个类型

  • 联合类型

    调用方法需要去调用它们的公有方法

  • 类型保护

    类型判断?

原文地址:https://www.cnblogs.com/daixixi/p/11306026.html