Skip to content

Record 类型

将一个类型的所有属性值都映射到另一个类型上并创造一个新的类型

ts
type Record<k extends keyof any, T> = {
  [P in K]: T
}

type petsGroup = "dog" | "cat" | "fish"
interface IPetInfo {
  name: string
  age: number
}

type IPets = Record<petsGroup, IPetInfo>

/**
 *  IPets = {
 *     dog: IPetInfo
 *     cat: IPetInfo
 *     fish: IPetInfo
 *  }
 **/

const animalsInfo: IPets = {
  dog: {
    name: "dogName",
    age: 2
  },
  cat: {
    name: "catName",
    age: 3
  },
  fish: {
    name: "fishName",
    age: 5
  }
}

联合类型

一个值可以是几种类型之一
如果一个值是联合类型,我们只能访问此联合类型的所有类型里共有的成员。

ts
type unionType = number | string

interface Bird {
  fly()
  layEggs()
}

interface Fish {
  swim()
  layEggs()
}

type Animal = Bird | Fish
function getPet(): Animal {
  if (xxx) {
    return bird
  } else {
    return fish
  }
}
let pet = getPet()
pet.fly() // error

类型保护与区分类型

枚举

枚举是 enum 关键定义的数据

ts
enum enumVar = {
  x,
  y
}
// enumVar.x = 0
// enumVar[0] = 'x'
enum enumVar = {
  x = 'x'
  y = 'y'
}
// enumVar.x = 'x'
// enumVar['x'] = 'x'

高级类型

Partial

ts
type Partial<T> = {
  [P in keyof T]?: T[p]
}

Required

ts
type Required<T> = {
  [P in keyof T]-?: T[P]
}

ReadOnly

ts
type ReadOnly<T> = {
  readonly [P in keyof T]: T[P]
}

Pick

ts
type Pink<T, K extands keyof T> = {
  [P in K]: T[P]
}

Record

ts
type Record<K extends keyof any, T> = {
  [P in K]: T
}

Type

ts
interface Type<T> extends Function {
  new (...arg: any): T // 表示T只能被new 调用, 不能直接调用
}

可以看到 type 是不能继承的,而且写法是赋值, interface 更像是申明

装饰器

装饰器经计算后必须返回一个函数,就包括两种形式,一是直接返回函数,另一种是函数工厂

ts
function decorator(target) {
  return ...
}
function decoratorFactory() {
  return function(target) {}
}

装饰器会在 class 定义期间执行,无须等到 new

  1. 上至下依次对装饰器表达式求值(工厂函数会被执行)。
  2. 求值的结果会被当作函数,由下至上依次调用
ts
@g
@f
// g(f(x))
  1. 类装饰器(constructor)
  2. 方法装饰器(constructor, key,)
  3. 属性装饰器
  4. 参数装饰器

ReadonlyArray<> 和 Array<>

用于固定数组, 保证数组不能被修改或者被引用到另一个变量上

interface 理解

是对结构的描述

ts
interface Test {
  test(): boolean // 描述对象的中函数
  (a: string): boolean // 函数体的描述
  new (test: string): someInstanceInterface // 对构造函数的额描述
  [prop: number]: string  // 索引签名
}
interface Test1 extends Test // 接口是可继承的

interface Counter {    // 混合类型,类比有属性的函数
    (start: number): string;
    interval: number;
    reset(): void;
}

interface SomeConstructor {  // 对构造器进行描述,描述构造器和构造器上面的静态属性
  new (a: string): Counter
  test()
  propA: string
}

对象字面量传参问题

对象字面量会被特殊对待而且会经过 额外属性检查,当将它们赋值给变量或作为参数传递的时候。 如果一个对象字面量存在任何“目标类型”不包含的属性时,你会得到一个错误

ts
interface Config {
  width?: string
  height?: string
}
function test(config: Config): { width: string } {}

test({ height: 123, a: 123 }) // a会报错

解决方法是提前为 额外的属性进行 定义

ts
  interface Config {
    ...
    [prop: string]: string
  }

函数的 interface 仅用于表达式声明中

ts
interface Func {
  (arg1: string, arg2: number): void // 对函数体描述
}
let func: Func = function(a: string, b: string): void {} // 参数名可以和接口不一致

可索引的类型

仅包括数字索引和字符串索引, 数字索引的值必须是字符串索引的子类型,因为 JavaScript 中 a[100]===a['100']

ts
interface SomeInterface {
  [prop: string]: number
  [prop: number]: string
}

readOnly 的理解

针对对象的属性名进行锁定,在索引签名中,可以对索引锁定readonly [prop: string]: string,对象不能在新增加属性

interface 的种类

  1. 对象类型
  2. 函数类型
  3. class 类型

class interface 的写法

ts
// ? PersonConstructor 是用来检查静态部分的
interface PersonConstructor {
  new (name: string, age: number) // ✔️ 这个是用来检查 constructor 的
  typename: string // ✔️ 这个是用来检查静态属性 typename 的
  logname(): void // ✔️ 这个用来检查静态方法 logname 的
}
// ? PersonInterface 则是用来检查实例部分的
interface PersonInterface {
  // new (name: string, age: number) // ❌ 静态方法的检查也不能写在这里 这样写是错误的
  log(): void // : 这里定义了实例方法 log
}

// class Person implements PersonInterface, PersonInterface { ❌ 这样写是错误的
const Person: PersonConstructor = class Person implements PersonInterface {
  name: string
  age: number
  static typename = "Person type" // 这里定义了一个名为 typename 的静态属性
  static logname() {
    // 这里定义了一个名为 logname 的静态方法
    console.log(this.typename)
  }
  constructor(name: string, age: number) {
    // constructor 也是静态方法
    this.name = name
    this.age = age
  }
  log() {
    // log 是实例方法
    console.log(this.name, this.age)
  }
}

const Person: PersonConstructor

接口可以继承 class

当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的 private 和 protected 成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)。

ts
interface someInterface extends someClass // 会继承class中所有的成员,实例属性和方法

对上一条的理解

当我们比较带有 private 或 protected 成员的类型的时候,情况就不同了。 如果其中一个类型里包含一个 private 成员,那么只有当另外一个类型中也存在这样一个 private 成员, 并且它们都是来自同一处声明时,我们才认为这两个类型是兼容的。 对于 protected 成员也使用这个规则

就是说需要都是某一个基类的子类才行

受保护的构造函数

对构造添加 protected,pretected 能被子类访问, private 不能被子类访问

类中的 readonly

你可以使用 readonly 关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。

typeof class

返回一个 类的 静态成员信息和实例化对象的构造函数信息 (静态信息部分)

ts
class Greeter {
  static standardGreeting = "Hello, there"
  greeting: string
  greet() {
    if (this.greeting) {
      return "Hello, " + this.greeting
    } else {
      return Greeter.standardGreeting
    }
  }
}

var greeter1: Greeter
greeter1 = new Greeter()
alert(greeter1.greet())

var greeterMaker: typeof Greeter = Greeter // Greeter 包括了静态信息部分和动态信息部分,所以满足typeof
greeterMaker.standardGreeting = "Hey there!"
var greeter2: Greeter = new greeterMaker() // new greeterMaker返回动态信息,所以蛮子 Greeter, 是class 本生作为类型, 应该指的是示例部分
alert(greeter2.greet())

函数定义类型

详情参见函数类型写法

  1. 在申明时给每个参数和返回标记处类型,并写函数体
ts
function a(arg1: string): boolean

let a: (arg1: string) => boolean = func
  1. 使用 type

ts
// 写法一
function Func(a: string)=>boolean;

// 写法二
let a: (b: string) => boolean = function(a: string) {
  return true
}

// 写法三

interface Func1 {
  (a: string): boolean
}

TypeScript 里的每个函数参数都是必须的

不能传 null 和 undefined

interface 可以缩写, 直接在用的地方定义

ts
interface SomeInterface {
  (a: string): boolean
}

let a: { (a: string): boolean } = function(a: string) {
  // 这两种是等价的、
  return false
}

泛型

在定义中函数或者 interface 前面, 使用时在后面

ts
// 泛型接口
interface {
  <T>(a: T): T
}
// 泛型类
class Add<T> {
  value: Array[T]
  consturctor(value:T) {
    this.value= [value]
  }
}
// 泛型约束
interface With<T, name> {
  name: T
}
class Add<T extends WithNumber<string, "number">>

泛型仅包括泛型接口和泛型类

ts 需要区分运行时和编译时

interface 和 const enum 就会在编译时被抹掉, enum 会被计算到生成的代码中, interface 仅作为检查。

ts
const enum EnumA {
  A,
  B,
  C
}
const test = [EnumA.A]
// => 生成的js 代码
const test = [0]

typeof 变量

可以推导出变量 A 的类型, 用于复制某一变量的类型

ts
type typeA = typeof varA