TS 基础

TS基础

TS环境

安装ts : npm i -g typescript
编译ts文件: tsc test.ts

类型

类型声明
let a : number

let b : string = '123'

function func(c : boolean) : string {
  return c ? '123' : '321'
}
类型介绍
number、string、boolean
字面量

描述变量的值为类型的本身

let d : 'A'  |  true  |  2
d = 'A'
d = true
d = 2
any
let a : any

表示任意类型,一个变量设置类型为any后视为放弃TS类型检测,相当于JS

let a

如果声明变量不指定类型,TS解析器会将该变量视为any

let d : 'A' | true | 2
let e : any
d = e

当变量的类型为any时,赋值给任何类型的变量都不会报错

unknown

类型为unknown的变量,可以给自己赋值任何类型的值,但不能直接赋值给其他变量

let d : 'A' | true | 2
let e : unknown
if(e === 'A'){
  d = e
}

let a : string
let b : unknown
if(typeof b === 'string'){
  a = b
}
void

用来表示空,一般用在函数返回值,表示没有返回值

function func() : void{
  return null
}
function func1() : void{
  return undefined
}

没有返回值的函数,默认分配void类型

function warnUser() {
  console.log("This is my warning message");
}
never

表示变量某种不可能存在的情况

const a = 123;
if (a !== 123) {
    const b = a;    // b: never
}

表示函数永远不会返回结果,但是可用来做抛出错误的函数

function func1() : never{
  throw new Error('错误')
}

function fun2(): never {
  return process.exit(1)
}

function fun3(): never {
  while (true) {
  }
}

某些时候never可以用来检查代码是否严谨或者是否遗漏
举例:

type All = string  |  number
function handle(val : All) {
  switch (typeof val) {
    case 'string':
    break;
    case 'number':
    break;
    default:
    const a :  never = val    
    break;
  }
}

object
let a : object
a = { }
a = function () { }
let a:{name : string,age? : number,sex? : string}
a = {name : '111',sex : '男'}
let a : {name : string , [propName : string] : any}
a = {name : '111',age : 12, true : 1, 1 : '123'}
let d : (a : number, b : number) => number
d = function (n1 : number,n2 : number):number {
  return 0
}
array

数组

let a : string[ ]
a = [ 'a' , 'b' , 'c']

let b : Array<number>
b = [1, 2, 3]

let c : (string | number | boolean)[ ];
c = [1 , 1, 'a', true]
tuple 元组

长度、类型、顺序固定的数组

let a: [string, number, boolean]
a = ['1', 1, false]
enum 枚举

列举一些类型

enum MyType {
  A = 1,
  B,
  C
}

let a : MyType
a = MyType.A
enum MyType{
  A = 100,
  B = 99,
  C
}
console.log(MyType.A === MyType.C);//true
类型断言
let a : string
let b : unknown
a = b as string
a = <string>b
  • 变量 as 类型
  • <类型>变量

类型别名

对于一些复杂的自定义类型,可以用type声明的变量来接收

type mytype = { name : string } & { age : number} & { gender : string}
let a : mytype = {
  name : 'zza',
  age : 26,
  gender : '男'
}

接口

interface myInterface {
  name:string,
  age:number
}
  • 是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)
  • 在TypeScript中,我们使用接口(Interfaces)来定义对象的类型。除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述

接口是为变量或者类制定一个规则或者标准,实现时需要去遵守。

变量声明接口类型时,属性要保持一致

const a : myInterface = {
  name:'zza',
  age:26
}

类实现接口时,属性实现可以多但不能少

class myClass implements myInterface{
  name: string
  age: number
  gender: string
  getInfo():string{
    return this.name
  }
}
可选属性
interface myInterface {
  name:string,
  age:number,
  gender?:string
}
只读属性
interface myInterface {
  name:string,
  age:number,
  readonly gender:string
}

const 用来修饰变量,readonly 用来修饰属性

任意属性

一般用在对象变量上

interface myInterface {
  name:string,
  age:number,
  [propName: string]: number | string;
}
const a : myInterface = {
  name:'zza',
  age:26,
  addr:'123'
}

用在类中,意义不大

class myClass implements myInterface{
  name: string 
  age: number 
  [propName: string]: number | string
  constructor(name:string,age:number,propName:number | string){
    this.name = name
    this.age = age
    this.propName = propName
  }
}

const obj = new myClass('zza',26,12)//myClass {name: "zza", age: 30, propName: 12}
console.log(obj);
可索引属性
interface myInterface {
  name:string,
  age:number,
  [propName: number]: number
}
const a : myInterface = {
  name:'zza',
  age:26,
  123:0
}
接口继承

extends

interface myInterface {
  name:string,
  age:number,
}
interface myInterface2 extends myInterface{
  addr:string
}

class myClass {
  phone:string
  emil:string
}
interface myInterface3 extends myClass{
  call():void;
}
类型别名和接口的区别
  1. 写法区别
type A = number;
type B = A | string | 'A'
interface A {
  name: string
}

合并写法

type A = {
  name:string,
  age:number
}
type B = A & {
  gender:string
} 
interface A {
  name:string,
  age:number
}
interface B extends A {
  gender:string
} 
  1. 重复声明
    类型别名重复声明会报错
interface A {
  name:string,
  age:number
}
interface  A {
  gender:string
} 

class A {
  name : string
  constructor(name:string){
    this.name = name
  }
  getInfo(){
    console.log(this.name);
  }
}

class B extends A {
  age:number
  constructor(name:string, age:number){
    super(name)
    this.age = age
  }
  getInfo() {
    super.getInfo()
    console.log(this.age);
  }
}

const a = new B('zza',26)
console.log(a);
a.getInfo()
readonly 修饰符
  • 只读属性必须在声明时或构造函数里被初始化。
class Person {
  readonly name: string = 'abc'
  constructor(name: string) {
    this.name = name
  }
}

let john = new Person('John')
公有、私有、受保护的修饰符
public 公有

属性和方法默认为公有,自己、类外和子类均可调用

private 私有

属性和方法只能在自己类中调用

protected 受保护的

属性和方法可以在自己和子类中调用

class Person {
  protected name: string;
  constructor(name: string) {
      this.name = name;
  }
  protected getName():string{
    return this.name
  }
}

class Employee extends Person {
  private department: string;

  constructor(name: string, department: string) {
      super(name);
      this.department = department;
  }

  getWorkInfo() {
      return `我叫${this.getName()},我工作在${this.department}`;
  }
}

let aEmployee = new Employee('durban', '华盛顿');
console.log(aEmployee.getWorkInfo());

注意:readonly 与 上述修饰符不冲突,可以联合使用

存取器
class A{
  private _name:string 
  constructor(name:string){
    this._name = name
  }
  get name(){
    return this._name
  }
  set name(value:string){
    this._name = value
  }
}
静态成员
  • 用static修饰的属性或方法
  • 存在于类本身而不是类的实例上
class Person {
  name1: string = 'A'
  static name2: string = 'B'
}

console.log(Person.name2)
console.log(new Person().name1)
  • 在静态方法中可以调用静态的属性和方法,也可以调用this(可以将非静态的属性暴露),但不能用this获取非静态方法
class A {
  private static age:string = '26'
  private name:string = 'zza'
  getInfo(){
    return this
  }
  static getStaticInfo(){
    return this
  }
}

console.log(A.getStaticInfo());
console.log(new A().getInfo());
  • 类中有个内置的只读属性name,属于静态属性,在类中可以再声明一个name属性但不能修饰为静态属性。
抽象类
  • 用abstract修饰的类是抽象类
  • 抽象类不能用来实例化对象,只能作为父类供子类来继承
  • 抽象类中可以添加普通属性和方法,也可以添加抽象属性和方法
  • 被抽象的属性和方法不允许有值或实现,也不允许被constructor赋值
  • 如果继承抽象类的子类不是抽象类,就必须将其中所有的抽象属性和方法具体化
abstract class Animal {
  abstract name:string 
  constructor() {
  }
  abstract say():void;
  run():void{
    console.log('跑');
  }
}

abstract class sAnimal extends Animal{
  abstract age:number
}

class Dog extends sAnimal {
  name: string;
  age: number;
  run(): void {
    super.run()
  }
  say(): void{
    console.log('叫');
  }
}
多态
abstract class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  abstract eat(): any;
  run() {
    console.log('动物跑');
  }
}

class Cat extends Animal {
  eat() {
    return "吃鱼";
  }
}
class Dog extends Animal {
  eat() {
    return "吃肉";
  }
  // run() {
  //   console.log('狗跑');
  // }
}


var cat: Animal = new Cat("猫");
var dog: Animal = new Dog("狗");

let fun: (x: Animal) => void = (x: Animal) => {
  console.log(x.name + x.eat());
}

fun(cat)
fun(dog)

cat.run()
dog.run()
接口和抽象类的区别

区别:

  • 接口使用implemets实现,抽象类使用extends继承
interface A {
  name : string
}

class B implements A {
  name: string //必须
  age : string
}
abstract class A {
  abstract name : string
} 

class B extends A {
  name: string //必须
  age : number
}
  • 接口可以实现多个,以","分开,而继承只能有一个
interface A1 {
  name : string
}
interface A2 {
  age : number
}
interface A3 {
  gender : string
}
class B implements A1,A2,A3 {
  name: string //必须
  age : number //必须
  gender: string //必须
}
  • 抽象类中,可以有抽象方法及非抽象方法,接口中只能有抽象方法
abstract class A {
  abstract name : string
  addr:string
} 

class B extends A {
  name: string //必须
  addr:string //非必须
  age : number
}
  • 抽象类可以继承抽象类也可以实现接口,而接口只可以继承接口和类,不可以实现接口和类

共同点:

  • 都有抽象方法,都需要被实现
  • 都不能实例化
  • 抽象类可以被继承,接口也能被继承

函数

js:

// 命名函数
function fun1(x, y) {
  return x + y
}

// 匿名函数
let fun2 = function(x, y) { 
  return x + y;
}

ts中增加类型声明:

function fun1(x: number, y: number): number {
  return x + y
}

let fun2 = function(x: number, y: number): number { 
  return x + y
}

对于给变量指定类型赋值的完整写法

let myAdd2: (x: number, y: number) => number = 
function(x: number, y: number): number {
  return x + y
}
可选参数和默认参数
function fun(a: string='A', b?: string): string {
  if (b) {
    return a + '-' + b
  } else {
    return a
  }
}

console.log(fun('1', '2'))
console.log(fun('3'))
console.log(fun())
剩余参数
function letters(x: string, ...args: string[]) {
  console.log(x, args)
}
letters('abc', 'c', 'b', 'a')
函数重载
// 重载函数声明
function add (x: string): string
function add (x: number): number

// 定义函数实现
function add(x: string | number): string | number {
  if (typeof x === 'string') {
    return x
  } else if (typeof x === 'number') {
    return x
  }
}
const a : number = add(1)
const b : string = add('1')
console.log(a)
console.log(b)

泛型

  • 指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型的一种特性。
函数泛型
function fun<T,K>(a:T,b:K):T{
  console.log(b);
  return a 
}

fun<string,number>('123',123)

实际使用:

function getNumberArr(value:number,count:number):number[] {
  const a : number[] = []
  for(let i = 0;i < count;i++){
    a.push(value)
  }
  return a
}

function getStringArr(value:string,count:number):string[] {
  const a : string[] = []
  for(let i = 0;i < count;i++){
    a.push(value)
  }
  return a
}


const arr = getNumberArr(123,10)
console.log(arr[0].toFixed());

const arr2 = getStringArr('123',10)
console.log(arr2[0].length);

利用泛型:

function getArr<T>(value:T,count:number):T[] {
  const a : T[] = []
  for(let i = 0;i < count;i++){
    a.push(value)
  }
  return a
}
const arr3 = getArr<string>('123',10)
const arr4 = getArr<number>(123,10)
console.log(arr3[0].length);
console.log(arr4[0].toFixed());
泛型接口
  • 在定义接口时,为接口中的属性和方法定义泛型类型,在使用接口时,再指定具体的泛型类型
interface A <T> {
  arr:T[]
  value:T
}

class B implements A<number>{
  arr:number[]
  value: number
}

使用例子:

interface IbaseCRUD <T> {
  data: T[]
  add: (t: T) => void
  getById: (id: number) => T
}

class User {
  id?: number; //id主键自增
  name: string; //姓名
  age: number; //年龄

  constructor (name, age) {
    this.name = name
    this.age = age
  }
}

class UserCRUD implements IbaseCRUD <User> {
  data: User[] = []
  
  add(user: User): void {
    user = {...user, id: Date.now()}
    this.data.push(user)
    console.log('保存user', user.id)
  }

  getById(id: number): User {
    return this.data.find(item => item.id===id)
  }
}


const userCRUD = new UserCRUD()
userCRUD.add(new User('tom', 12)) 
userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)
泛型类
  • 在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型
class A <T> {
  default:T
  add:(x:T,y:T) => T
}

const a = new A<number>()
a.default = 1
a.add = (x:number,y:number) =>{
  return x + y
}

const b = new A<string>()
b.default = '1'
b.add = (x:string,y:string) =>{
  return x + y
}
泛型约束
function fn <T>(x: T): void {
  console.log(x.length)  // 报错
}

这时需要一个规则来约束这个泛型T ,让他可以使用length属性

interface B {
  length:number
}

function fn <T extends B>(x: T): void {
  console.log(x.length)  // 报错
}

注意:泛型约束中的extends意义上和实现相同,指T必须拥有接口B中的属性和方法

interface B {
  length:number,
  add:(a:number,b:number)=>number
}

function fn <T extends B>(x: T): void {
  console.log(x.length) 
  console.log(x.add(100,200));
  
}

class C implements B{
  length: number
  add: (a: number, b: number) => number
}

fn<C>(
  {
  length:2,
  add:(x,y)=>{
    return x+y
  }
}
)

泛型工具

keyof

interface Foo {
  name: string;
  age: number
}
type T = keyof Foo // -> "name" | "age"

const a : T = "name"
const b : T = "age"

type A = keyof any  //  type A = string | number | symbol

in

type Keys = "a" | "b"
type Obj =  {
  [p in Keys]: any
} // -> { a: any, b: any }

const a : Obj ={
  a:'123',
  b:123
}

infer

  • infer 声明一个类型变量并且对它进行使用,仅条件类型的 “extends” 子句中才允许 “infer” 声明。
type A<T> = T extends (x: any) => infer P ? P : T;

type B = (x:number)=>number

const a : A<string> = '123'
const b : A<B> = 2
Partial 作用是将传入的属性变为可选项
type myPartial<T> = { [P in keyof T]?: T[P] };

interface A {
  a:string
  b:string
}
const a: myPartial<A> = {
  a:'132',
  // b:'123'
}
Required 作用是将传入的属性变为必选项
type myRequired<T> = { [P in keyof T]-?: T[P] }


interface A {
  name:string
  age:number
  addr?:string
}

const a : myRequired<A> ={
  name:'zza',
  age:26,
  addr:'qewr'
}
Record 后面的泛型就是对象键和值的类型
type myRecord<K extends keyof any, T> = { [P in K]: T };

const a : myRecord<string,number> = {
  // name:'zza',  报错
  age:26
}
Pick 从 T 中取出 一系列 K 的属性
type myPick<T, K extends keyof T> = { [P in K]: T[P] };

interface A {
  name:string,
  age:number,
  addr:string
}

type B = 'name' | 'age'

const a : myPick<A,B> = {
  name:'zza',
  age:26
}
ReturnType 获取返回值类型
type myReturnType<T> = T extends (...args: any[]) => infer R ? R: T;

type B = (x:number)=>number

const a : myReturnType<string> = '123'
const b : myReturnType<B> = 2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值