TypeScript 高级类型

一、高级类型

  • class
  • 类型兼容性
  • 交叉类型
  • 泛型和keyof
  • 索引签名类型和索引查询类型
  • 映射类型

二、class

  • 构造函数给变量赋值
  • extends 继承
  • implement 实现接口
  • public 公开,所有可见,默认,可以省略
  • protected:仅仅自己和子类可用
  • private:私有的,只有自己可用
// 感叹号表示虽然没有初始化,但一定会有值
class Person {
  name!: string
  gender = '男'
}

let p = new Person()
p.name = '小乔'
p.gender = '女'
console.log(p)

class Person {
  name: string
  gender: string
  age: number
  constructor(name: string, gender: string, age: number) {
    this.name = name
    this.age = age
    this.gender = gender
  }
  setName: (name: string) => void = (name) => {
    this.name = name
  }
  setAge(age: number) {
    this.age = age
  }
}

let p = new Person('大乔', '女', 18)

interface IAction {
  say(): void
}
class Animal {
  age!: number
}
class Dog extends Animal implements IAction {
  constructor(age: number) {
    super()
    this.age = age
  }
  say(): void {}
}

console.log(new Dog(17))
  • readonly:只读修饰符,防止在构造之外的赋值行为,但是必须指定类型,否则为字面值常量
class Person {
  readonly age: number = 18
  constructor(age: number) {
    this.age = age
  }
}

三、类型兼容性

  • 同类型的兼容
(method) Array<number>.forEach(callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any): void

// 有三个变量,所以以下方法兼容
let arr = [1, 2, 3, 4, 5, 6]
arr.forEach((item, a) => {
  console.log(a + '、' + item)
})

  • 成员多的可以赋值给成员少的
  • 成员少的兼容成员多的
class Point {
  x: number
  y: number
}
class Point3D {
  x: number
  y: number
  z: number
}
let p: Point = new Point3D()
  • 接口、函数都有兼容性
interface Point {
  x: number
  y: number
}
interface Point2D {
  x: number
  y: number
}
interface Point3D {
  x: number
  y: number
  z: number
}
// 接口必须赋值后,才能给另一个变量
let p1: Point = { x: 1, y: 2 }
let p2: Point2D = { x: 4, y: 5 }
let p3: Point3D = { x: 6, y: 7, z: 8 }
p1 = p2
p2 = p3
console.log(p1, p2, p3)
  • 类和接口只要类型相同也可以兼容
interface Point {
  x: number
  y: number
}
class Point2D {
  x: number
  y: number
  constructor(x: number, y: number) {
    this.x = x
    this.y = y
  }
}
interface Point3D {
  x: number
  y: number
  z: number
}

let p1: Point = { x: 1, y: 2 }
let p2: Point2D = new Point2D(4, 5)
let p3: Point3D = { x: 6, y: 7, z: 8 }
p1 = p2
p2 = p3
console.log(p1, p2, p3)

四、交叉类型

  • 交叉类型的功能类似于接口继承
  • 用于组合多个类型为一个类型(常用于对象类型)
class Person {
  name = "";
  age = 0;
}
class Point {
  x = 0;
  y = 0;
}
type Temp = Person & Point;
let p: Temp = { name: "", age: 0, x: 0, y: 0 };
p.name = "张三";
console.log(p);

五、泛型

  • 在保证类型安全的前提下,实现复用
  • 利用类型推断机制,可以简化泛型调用
function Say<T>(t: T) {
  console.log(typeof t, t);
}
Say<number>(19);
Say<string>("张三");
// 可以简化泛型类型调用
Say(29);
Say("李四");
  • 泛型约束
    • 指定具体类型
    • 添加约束 extends
// 指定具体类型,就会有length的属性
function Say<T>(t: T[]) {
  console.log(typeof t, t, t.length);
}

Say([29, 90, 25]);
Say(["李四", "王五"]);

// 添加约束,要求传入的参数必须具有length属性
interface ILength {
  length: number;
}
function Say<T extends ILength>(t: T) {
  console.log(typeof t, t, t.length);
}

Say([29, 90, 25]);
Say(["李四", "王五"]);
  • 泛型接口
  • ctrl+鼠标左键或者F12键,查看定义
interface IdFun<T> {
  id: (v: T) => T
  ids: () => T[]
}
let a: IdFun<number> = {
  id(v) {
    return v
  },
  ids() {
    return [1, 2, 3, 4]
  },
}

console.log(a.id(6))
console.log('ids :>> ', a.ids())
  • 泛型类
class GenericNumber<T> {
  defaultNum: T
  add: (a: T, b: T) => T
  constructor(v: T) {
    this.defaultNum = v
  }
}
// 因为有构造,所以能自动推断出类型,如果没有就需要显式指定类型
const myGenericNum = new GenericNumber(10)
myGenericNum.defaultNum = 0
myGenericNum.add = (a, b) => {
  return a + b
}
  • 泛型工具类
  • Partial<T>
  • Readonly<T>
  • Pick<T, keys>
  • Record<Keys, T>:构造一个对象类型,属性为k,类型为T
interface Props {
  name: string
  age: number
}
// 原有类型没有发生变化,生成一个新类型,新类型每个属性都是可选类型
type propsNew = Partial<Props>
let a: propsNew = {}

// 将所有属性变成只读
type propReadonly = Readonly<Props>
let b: propReadonly = { name: '张三', age: 10 }

// 从中选择一些属性,两个参数
type propPick = Pick<Props, 'name' | 'age'>
let c: propPick = { name: '', age: 10 }
c.name = '李四'
c.age = 18

// 构造一个新类型,属性键为keys,属性每个类型为T
type RecordObj = Record<'a' | 'b' | 'c', string[]>
let d: RecordObj = {
  a: [''],
  b: [''],
  c: [''],
}
type RecordObj2 = Record<'a' | 'b' | 'c', number>
let e: RecordObj2 = {
  a: 1,
  b: 2,
  c: 3,
}

六、索引签名类型和索引查询类型

  • 当无法确定对象中有哪些属性时,用索引签名类型
  • key只是个占位符,可以换成任意类型
interface ObjAny {
  [key: string]: number;
}

let a: ObjAny = {
  a: 1,
  b: 2,
  hello: 6,
};

// Array<T> 就有这种用法,仿造的
interface MyArray<T> {
  [k: number]: T;
}
let c = [1, 2, 4, 7];
  • 映射类型
    • 基于旧类型创建的新类型,减少重复,提高开发效率
    • 该类型是基于索引签名类型的
    • key in P:key可以是P属性中的任意一个
    • 只能在类型别名中使用,不能在接口中使用
// 复合类型
type P = "a" | "b" | "c";
type M = { [key in P]: number };
let temp: M = {
  a: 1,
  b: 2,
  c: 4,
};
let d = [1, 3, 4, 5, 8, 2];

// 对象中获取
type Person = {
  name: string;
  age: number;
  birth: Date;
};
type H = { [key in keyof Person]: number };
  • 系统内置的映射类型
    • keyof T 表示获取泛型的所有键
    • []后面的问号,表示是可选的
    • 冒号后面的T[P]表示获取T中每个键对应的类型
type Required<T> = {
    [P in keyof T]-?: T[P];
};

/**
 * Make all properties in T readonly
 */
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};
  • T[P]:属于索引查询类型或索引访问类型
// 获取person中age的类型
type f = Person["age"];
posted @ 2022-10-24 20:48  his365  阅读(21)  评论(0编辑  收藏  举报