typescript高級類型部分代碼記錄

TS中的類

// 類的可選參數 
class Info {
  public name: string
  public age?: number
  public readonly hobby: number[]
  // 申明再constructorconstructor 參數傳遞過來自動賦值 this.sex = sex
  constructor(name: string, age?: number, public sex?: string) {
    this.name = name
    this.age = age
  }
}

// 抽象類只提供方法的定義 繼承的類須要去實現對應的定義
abstract class People {
  public abstract age: number
  constructor(public name: string) { }
  abstract getName(): string
  abstract get insideAge() :string
  abstract set insideAge(value:string)
}

class Man extends People {
  public age: number
  public insideAge:string
  public getName(): string {
    return '123'
  }
}


// 接口檢測的 是使用該接口定義的類的實例 根據實例上屬性來判斷
interface footInterface { 
  name:string
}

class Foot implements footInterface { 
  public name : string
}


// 接口能夠繼承類

class A { 
  public name: string
  protected hobby:Array<string>
  private age:number
}
interface I extends A { }

// 直接實現接口會有問題,若是全是public就不會,若是存在保護 私有的類型 就須要先繼承再實現
class B extends A implements I { 
  public name: string
  protected hobby: Array<string>
}

// 接口繼承類,若是全是public定義的屬性,這裏就不會報錯,可是存在private protected定義的就會有問題
var n: I = {
  name: 'ccc',
  age: 123,
  hobby:['1']
}

// 久久不能理解的一個寫法 實例的類型就是這個類

function createObj<T>(obj: new () => T): T { 
  return new obj() // 類型建立的實例 類型也就是這個類
}
class C { 
  public name:string
}
const c : C = createObj(C)

高級類型

// 類型斷言 ! 表示不爲 null
function getString(num: number | null): string { 
  function test(prefix:string) { 
    return prefix + num!.toFixed().toString()
  }
  num = num || 0.1
  return test('hello')
}

// never 配合 switch的使用
// 能夠檢測當前的判斷條件是否使用完,而且傳入未知類型的時候拋錯
function assertNever(err: never): never {
  throw new Error('type error' + err)
}
type circle = {
  type: 'circle'
  radius: number
}
type rance = {
  type: 'rance'
  width: number,
  height: number
}
type area = circle | rance
function computeAreaArea(area: area) {
  switch (area.type) {
    case 'circle' :
      return area.radius ** 2 * Math.PI 
    case 'rance':
      return area.height * area.width
    default :
      return assertNever(area)
  }
}


// 將一個對象的值轉換爲get set的形式
type proxy<T> = {
  get(): T,
  set(v): void
}

type proxify<T> = {
  [P in keyof T]: proxy<T[P]>
}


function transform<T>(obj: T): proxify<T> {
  let result = {} as proxify<T>
  for (var key in obj) {
    result[key] = {
      get: () => {
        return obj[key]
      },
      set: (value) => {
        result[key] = value
      }
    }
  }
  return result
}

function unTransform<T>(obj: proxify<T>): T {
  let result = {} as T
  for (var key in obj) {
    result[key] = obj[key].get()

  }
  return result
}

// 快速增長移除特定限制 可選 只讀
// -readonly 移除readonly -? 移除可選
type Remove<T> = {
  -readonly [P in keyof T]-?: T[P]
}


// 動態數據類型 根據三目運算來動態決定類型
type TypeName<T> = T extends string ? string :
  T extends number ? number :
  T extends () => void ? () => void : object

let dynamaticType1: TypeName<string> // string
let dynamaticType2: TypeName<number> // number
let dynamaticType3: TypeName<(() => void) | number> // number | ()=>void

// keyof 會排除類型爲 null undefined never 
// 理解下面這個寫法 [1]將T中的類型先修改了 [2]再使用[keyof T]來過濾掉屬性(第一步中已經修改了)
type Type7<T> = {
  [P in keyof T] : T[P] extends Function ? T[P] : undefined
}[keyof T] 

interface type8 { 
  a: number
  b():void
}
let abc: Type7<type8>

// infer 條件類型推斷
// 傳入四個類型 若是類型是一個數組,那麼返回數組的某一項的類型 number 索引訪問
type Type8<T> = T extends any[] ? T[number] : T
let T1: Type8<string[]> // string
let T2: Type8<number> // number

// infer 的寫法
type Type9<T> = T extends Array<infer U> ? U : T // infer 指向的是構成這個數組的數據類型
let T3: Type9<Array<{ a: 1, b: 2 }>> // {a:1,b:2} 其餘測試用例如上

let T4 : Exclude<'a' | 'b' | 'c','a' | 'b'> // 剩下'c', 排除相同的 
let T5: Extract<'a' | 'b' | 'c', 'a' | 'b'> // 剩下 'a' 'b' 選取相同的
let T6: NonNullable<null | undefined | number | string> // number | string 去除 null undefined
let T7: ReturnType<() => number> // 根據傳入的函數返回函數的返回值做爲類型

class Aclass { 
}

let T8: InstanceType<typeof Aclass> // 
let T9: Aclass

interface type 都支持嵌套寫法

// interface 寫法
interface Ip {
  name: string;
  child?: Ip;
}

let child: Ip = {
  name: "str",
  child: {
    name: "test"
  }
};

// type 寫法
type Ip = {
  name: string;
  child?: Ip;
};

let child: Ip = {
  name: "child",
  child: {
    name: "haha"
  }
};
// 有趣的寫法
type LinkedList<T> = T & { next: LinkedList<T> }; // people = {name:'',next:{name:'',next:{...}}}
interface Person {
  name: string;
}
var people: LinkedList<Person>;
var s = people.name;
var s = people.next.name;
var s = people.next.next.name;
var s = people.next.next.next.name;


// never 配合 switch的使用
// 能夠檢測當前的判斷條件是否使用完,而且傳入未知類型的時候拋錯
function assertNever(err: never): never {
  throw new Error('type error' + err)
}
type circle = {
  type: 'circle'
  radius: number
}
type rance = {
  type: 'rance'
  width: number,
  height: number
}
type area = circle | rance
function computeAreaArea(area: area) {
  switch (area.type) {
    case 'circle' :
      return area.radius ** 2 * Math.PI 
    case 'rance':
      return area.height * area.width
    default :
      return assertNever(area)
  }
}

// keyof 只會返回不爲 null undefined never 的類型
interface EnumType { 
  a: never,
  b: undefined,
  c: null,
  d: number,
  e:object
}
type TypeEnumType = keyof EnumType // a | b | c | d | e
type TypeEnumType1 = EnumType[keyof EnumType] // number | object 去除了了3種假類型

type ReadonlyType<T> = {
  readonly [P in keyof T] ? : T[P]
}
let readOnly: ReadonlyType<EnumType> = {} // 將 EnumType 全部類型都變爲了了 只讀
  • 常量的寫法 與 交叉數據類型
interface I {
  name: "ccc";
}
interface P {
  age: "bbb";
}

var a: I & P = {
  name: "ccc",
  age: "bbb"
};
  • keyof 用法
// 獲取對象的屬性
function pluck<T, K extends keyof T>(o: T, names: K): T[K] {
  return o[names];
}

// 升級版
function pluck1<T, K extends keyof T>(o: T, names: K[]): T[K][] {
  return names.map(item => o[item]);
}

// keyof用法
interface Personal {
  name: string;
  age: number;
}
//keyof Personal ==> 'name' | 'age' 這種的聯合類型 可使用in來循環
let ppp: keyof Personal = "name";
let ppp1: keyof Personal = "age";
let ppp2: keyof Personal = "ss"; // error 值只能爲 name | age
  • keyof 用法二
    keyof 和 T[K]與字符串索引簽名進行交互。 若是你有一個帶有字符串索引簽名的類型,那麼 keyof T 會是 string。 而且 T[string]爲索引簽名的類型
interface Map1<T> {
  [key: number]: T;
}
let pp: keyof Map1<string>; // pp 類型爲number
let pp4: Map1<string>[0]; // 返回的類型是string

interface Map2<T> {
  [key: string]: T;
}
let pp1: keyof Map1<string>; // pp1 類型爲string
let pp3: Map2<number>["foo"]; // 返回的類型是number
  • keyof 用法 3 映射類型
// 經過這個類型生成一個只讀版本 in 內部使用了for---in循環
interface PersonPartial {
    name?: string;
    age?: number;
}
// 使用
type ReadonlyPersonPartial<T> = {
    readonly [key in keyof PersonPartial]: PersonPartial[key]
}
let b: ReadonlyPersonPartial<string> = {
    name: 'string',
    age: 123
}

type Map2<T> = {
    [key in keyof PersonPartial]?: T;
}
var a: Map2<string> = {
    name: '123',
}

// 封裝一些通用的版本
type BeNull<T> = {
    [P in keyof T]:T[P] | null
}

type BeEmpty<T> = {
    [P in keyof T]?:T[P]
}
  • 理解 extends in 相關的東西
interface a {
  name: string;
  age: number;
}
// T 至關於上面有 name | age
// [key in T] 循環 name age ,每個key就是name age 那麼 a[name],a[age] j
type b<T extends keyof a> = { [key in T]: a[key] };
let c: b<"name" | "age"> = {
  name: "123",
  age: 12
};
  • 內置的 pick record exclude的理解 慢慢來吧
// pick  的做用是傳入一個接口,返回接口裏面特定的字段類型
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
interface b { 
    name: string,
    age:number
}
let cc: Pick<b, 'name' | 'age'> = {
    name: 'cc',
    age:123
}

// 傳入屬性,生成一個接口 生成一個 name age 都是string的interface
type Record<K extends keyof any, T> = {
    [P in K]: T;
};
let mmm: Record<'name' | 'age', string> = {
    name: 'ccc',
    age:'20'
}

// 排除相同的 extends 能夠理解爲 T 能夠賦值給 U 能夠賦值返回never 不然 返回 T
type Exclude<T, U> = T extends U ? never : T;
interface a { 
    name:string
}
interface b { 
    name: string,
    age:number
}

interface c {
    name: string,
    age: number,
    hobby:any
}

// 這兩個東西表示出來了 是分開來搞的 首先 a extends b => a  b extends b=>never 因此返回的是 a
let nnn: Exclude<a | b, b> // 返回 a 
let nnnn: Exclude<a | b, a> // 返回 never  a extends a => never  b extends a b能夠賦值給a 返回never
let ccc: Exclude<a | b | c, c> 

let b: a extends b ? number : string  // a 不能賦值給 b 因此返回了string b的類型就是string
let nnn:Exclude<keyof b,keyof a> // 排除相同的事後 剩下的就是 ‘age’  'name'|'age' extends 'name'  難道是 name extends name , age extends name 分開來的 先這樣理解吧

type mm = 'number' | 'age';
type nn = 'age'
let c: mm extends nn ? never : mm; // mm 不能賦值給 nn 因此返回值是 mm 並非上面Exclude 返回的 age 這個能夠理解爲傳入泛型變量的時候ts 幫咱們去循環 extends(賦值了一下)

// 取出相同的
type Extract<T, U> = T extends U ? T : never; // T 能夠賦值給 U的話 表示的是T中的字段 U中確定都存在 返回了 U。
相關文章
相關標籤/搜索