TS珠峰 002【學習筆記】

泛型

/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2025-03-19 10:42:31
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2025-03-19 15:11:32
 * @FilePath: /ts-classes/src/index.ts
 * @Description: 這是默認設置,請設置`customMade`, 打開koroFileHeader查看配置 進行設置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
// 泛型

class Animal {
  constructor(public name: string, public age: number) {}
}

class Person {
  constructor(public name: string, public age1: number) {}
}
// ts中在使用的時候,可以通過
function createInstance<T>(c: { new (...args: any[]): T }, ...args: any[]): T {
  return new c(...args);
}

// const animal = new Animal('dog', 12);
// console.log(animal.name);
// console.log(animal.age);

const animal = createInstance<Animal>(Animal, 'dog', 12);
const person = createInstance(Person, 'Tom', 12);

// 類型不確定,我們可以根據泛型來確定類型
// 一定要注意ts是沒有執行呢,只是在編譯的時候會進行類型檢查
// 根據提供的數據生成對應長度的數組
function createArray<T>(length: number, value: T): T[] {
  return Array.from({ length }, () => value);
}

// 交換兩個變量的值
type ISwap = <T, U>(tuple: [T, U]) => [U, T];

interface ISwap2 {
  <T, U>(tuple: [T, U]): [U, T]; // 為甚麼<T, U>要寫在這裡,而不是在函數後面? 泛型使用的時候傳遞類型,可以推導,但是內部調用的時候沒有確定類型
}

// 寫在定義的前端,就表示使用類型的時候傳參,寫到函數的前端意味著函數調用的時候傳參
// 是在使用類型的時候傳遞泛型,還是在調用函數的時候傳遞泛型

const swap: ISwap = (tuple) => {
  return [tuple[1], tuple[0]];
};

const swapArray = swap<number, string>([1, '2']);

// 泛型是有默認值的,使用一些聯合類型的時候,會使用泛型
type UnionType<T = boolean> = T | number | string;
let union: UnionType = '123';
// 泛型約束 要求傳遞的參數必須符合要求 A extends B 表示A是B的子類(或同類型)
interface ILength {
  length: number;
}
// 甚麼叫子 甚麼叫父
function getLength<T extends ILength>(value: T) {
  // 只要我的對象里有length屬性,就可以
  return value.length;
}
getLength('123');
getLength({ length: 123 });

function getValue<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

getValue({ name: '張三', age: 12 }, 'age');

interface ILoginResponse<T> {
  code: number;
  message?: string;
  data: T;
}
interface ILoginData {
  token: string;
  userInfo: {
    name: string;
    age: number;
  };
  roles: string[];
}

function toLogin<T>(response: ILoginResponse<T>) {
  return response.data;
}

const loginResponse = toLogin<ILoginData>({
  code: 200,
  data: {
    token: '123',
    userInfo: {
      name: '張三',
      age: 12,
    },
    roles: ['admin', 'user'],
  },
});

// 類中使用泛型
class Cache<T> {
  private data: T[] = [];
  add(item: T) {
    this.data.push(item);
  }
}

const cache = new Cache<string>();
cache.add('123');
cache.add('456');

export {};

交叉類型

// & 交叉類型 | 聯合類型
// 將多個類型合併成一個類型

interface Person1 {
  handsome: string;
}

interface Person2 {
  high: string;
}

// 又高又帥的人 (交叉類型)
type Person = Person1 & Person2;

const person: Person = {
  // handsome: '帥',
  high: '高',
};
// 交叉類型可以賦給任意的父類型

export {};

unkown

// unknown 類型
// unknown 是any的安全類型,泛型沒有指定類型時,默認是unknown
let a: unknown;
// 默認情況下 unknown 必須要進行類型檢測才能使用(類型檢查或斷言)

// 類型斷言
let b = a as string;

// unknown 不能直接調用方法 需要加斷言

function processInput(val: unknown) {
  if (typeof val === 'string') {
    console.log(val.toUpperCase());
  } else if (typeof val === 'number') {
    console.log(val.toFixed(2));
  } else {
    console.log('unknown');
  }
}

let name: unknown = 'String字符串';
// name.toUpperCase(); // name是unknown類型,不能直接調用方法
(name as string).toUpperCase();

// unknown 在聯合或交叉類型中的特點
type UnionType = unknown | string; // unknown 類型
type IntersectionType = unknown & string; // string 類型

let union: UnionType = 'String字符串';
let intersection: IntersectionType = 'String字符串';

export {};

條件類型

// 條件類型
// 條件類型是TS中的一種類型運算符,它根據條件表達式的結果來選擇不同的類型

type ResStatusMessage<T extends number> = T extends 200 | 204 | 206
  ? 'success'
  : 'error';

// type R1 = ResStatusMessage<'abc'>; // 狀態碼肯定是數字,這樣傳也不會報錯
type R2 = ResStatusMessage<200>; // 狀態碼肯定是數字,這樣傳也不會報錯

type Condition<T, U> = T extends U ? 'success' : 'fail';
type R3 = Condition<'abc', string>; // 類型推斷為'success'
type R4 = Condition<'abc', number>; // 類型推斷為'fail'

// 條件類型在函數中的應用
interface Bird {
  fly: () => void;
}
interface Sky {
  name: '天空';
}
interface Fish {
  swim: () => void;
}
interface Water {
  name: '水';
}

type ConditionType<T> = T extends Bird ? Sky : Water;

type R5 = ConditionType<Bird>; // 類型推斷為Sky
type R6 = ConditionType<Fish>; // 類型推斷為Water

type FromatReturnType<T extends string | number> = T extends number
  ? number
  : T extends string
  ? string
  : never;
// 泛型一般代表輸入是不是確定(無限的)約束, 函數重載(有限的)
function sum<T extends number | string>(a: T, b: T): FromatReturnType<T> {
  // function sum<T extends number | string>(a: T, b: T):T {
  // 如果返回值是number類型,則返回number類型,如果返回值是string類型,則返回string類型 ,但這裡不能寫返回值T
  return a + (b as any); // T+T 不能確定 ,兩個泛型不能做數據運算
}

let r1 = sum(1, 2);
let r2 = sum('1', '2');

// 我們知道條件運算符,就可以掌握ts中的兼容性,以及類型的層級

// 類型層級
// 1. 基礎類型
// 2. 復合類型
// 3. 函數類型
// 4. 類類型

//兼容性:可以將一個值賦予給某個值
// 類型層級 低的層級可以賦予給高的層級

類型層級兼容

// 類型層級
// 1. 基礎類型
// 2. 復合類型
// 3. 函數類型
// 4. 類類型

// 我們知道了 條件運算符 就可以掌握ts中的兼容性 以及類型的層級
// 兼容性: 就是可以將一個值賦予給某個值
// 類型層級: 低的層級可以賦予給高的層級
// 理論,誰是父類型,誰是子類型
type R1 = 'abc' extends string ? true : false;
type R2 = 123 extends number ? true : false;
type R3 = true extends boolean ? true : false;
// 實戰 'abc' 是字符串類型, 123 是數字類型, true 是布爾類型
let r1: string = 'abc';
let r2: number = 123;

type R4 = 'a' extends 'a' | 'b' | 'c' ? true : false;
type R5 = 1 extends 1 | 2 | 3 ? true : false;
type R6 = true extends true | false ? true : false;

//
// 字面量類型可以賦值字面量聯合類型
let r4: 'a' | 'b' | 'c' = 'a';

// 包裝類型可以賦值給基礎類型
// let r5: string = new String('abc');

// 包裝類型
type R7 = string extends String ? true : false;
type R8 = String extends string ? true : false;
type R9 = number extends Number ? true : false;
type R10 = Number extends number ? true : false;
type R11 = boolean extends Boolean ? true : false;
type R12 = Boolean extends boolean ? true : false;

type R13 = Object extends any ? true : false;
type R14 = Object extends unknown ? true : false;
type R15 = never extends 'abc' ? true : false;

// never 是最小的類型
// 字面量類型可以賦予給字面量聞合類型
// 字面量類型可以賦予給基基礎類型
// 基礎類型是包裝類型的子類型
// any unknown 是最大的類型
// never<字面量類型<字面量聯合類型<基礎類型<包裝類型<Object<any unknown
type R16 = any extends string ? true : false; // true和false的聯合類型是boolean
// 針對any類型永遠返回的是成功和失敗的聯合類型;
// 低哦打可以賦予高的類型,
// 從結構上考慮 交叉類型,可以賦予 交叉前類型
// ts默認的 大小object是一樣的 Object extends object? true:false  反過來不一樣
// 結構上比你多,就可以賦予你
// 級別上 低級別可以賦予高級別
export {};

內置類型

正常判斷類型的時候,可以通過A extends B
條件分發(分發特性是默認開啓)

  1. A類型是通過泛型傳入的
  2. A類型如果是聯合類型會進行分發的
  3. 泛型參數A,必須是完全裸的(不是A & {}),才具備分發類型
// 條件類型在函數中的應用
interface Bird {
  fly: () => void;
}
interface Sky {
  name: '天空';
}
interface Fish {
  swim: () => void;
}
interface Water {
  name: '水';
}

type Condition = Fish | Bird extends Fish ? 'success' : 'fail'; // 類型推斷為'fail' 沒有分發
type Condition2<T> = T extends Fish ? 'success' : 'fail'; // 類型推斷為'success' 分發

type C3 = Condition2<Fish>; // success
// 分發就是挨個去比較
// Condition2<Bird> fail
// Condition2<Fish> success
type C4 = Condition2<Bird | Fish>; // success | fail
// 默認情況下有些時候我們需要關閉這種分發能力,會造成判斷不準確
// 怎麼消除這個分發類型 T & {}
type NoDistribute<T> = T & {};
// 不是裸類型,需要&{} 就喪失分發的能力,還可以加數組
type Condition5<T, U> = [T] extends [U] ? true : false;
type R5 = Condition5<1 | 2, 1>; // false

// T & {} 可以消除分發能力 甚麼也沒發生,只是為了T產生一個新類型
type IsNever<T> = T extends never ? true : false;
type R6 = IsNever<never>; // never 直接返回 never 數組包裹一下就是true了

//  內置類型
// 1. Extract 提取
type Extract<T, U> = T extends U ? T : never;
type R7 = Extract<1 | 2, 1>; // 1 分發 判斷
// 2. Exclude 排除
type Exclude<T, U> = T extends U ? never : T;
type R8 = Exclude<1 | 2, 1>; // 2 分發 判斷

// 3. NonNullable 非空
type NonNullable<T> = T extends null | undefined ? never : T;
type R9 = NonNullable<string | null>; // string

// 4. ReturnType 返回類型 infer 推斷 可以在條件類型中推斷出返回類型的某一部分
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type R10 = ReturnType<() => string>; // string

// 5. Parameters 參數類型
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
type R11 = Parameters<(name: string, age: number) => string>; // [string, number]

// 6. ConstructorParameters 構造函數參數類型
type ConstructorParameters<T> = T extends new (...args: infer P) => any
  ? P
  : never;
type R12 = ConstructorParameters<Error>; // [message?: string | undefined]

// 7. Partial 可選
type Partial<T> = {
  [P in keyof T]?: T[P];
};
type R13 = Partial<{ name: string; age: number }>; // { name?: string; age?: number }


// 條件類型在數組中的應用
type Swap<T> = T extends [infer A, infer B] ? [B, A] : T;
type R1 = Swap<['jw', 30]>; // 30 'jw'

// 條件類型在函數中的應用
type IsEqual<A, B> = A extends B ? (B extends A ? true : false) : false;
type R2 = IsEqual<1, 2>; // false
type R3 = IsEqual<1, 1>; // true

export {};
type Swap<T> = T extends [infer A, infer B] ? [B, A] : T;
type R1 = Swap<['jw', 30]>; // 30 'jw'
// 頭尾交換
type SwapHeadTail<T> = T extends [infer A, ...infer B, infer C]
  ? [C, ...B, A]
  : T;
type R2 = SwapHeadTail<[1, 2, 3, 4, 5]>; // [5, 2, 3, 4, 1]

// 條件類型在字符串中的應用
type IsString<T> = T extends string ? true : false;
type R14 = IsString<'jw'>; // true

// 條件類型在函數重載中的應用
type IsFunction<T> = T extends (...args: any[]) => any ? true : false;
type R15 = IsFunction<() => void>; // true

// promise的遞歸
type PromiseReturnType<T> = T extends Promise<infer P>
  ? PromiseReturnType<P>
  : T;

function getVal(): Promise<number> {
  return new Promise((resolve) => {
    resolve(100);
  });
}
type R16 = PromiseReturnType<ReturnType<typeof getVal>>; // true
// 通過infer來實現遞歸推導
// 將元組轉化成聯合類型[number,boolean,string] => number | boolean | string
type TupleToUnion<T> = T extends [infer A, ...infer B]
  ? A | TupleToUnion<B>
  : T;
type R17 = TupleToUnion<[number, boolean, string]>; // number | boolean | string

// 將聯合類型轉化成元組類型
type UnionToTuple<T> = T extends infer P ? [P] : never;
type R18 = UnionToTuple<number | boolean | string>; // [number] | [boolean] | [string]

// 重構類型結構 Partial Required Readonly Pick Omit Record

interface Person {
  name: string;
  age: number;
  gender: string;
}
let person: Partial<Person> = {
  name: 'jw',
};

function mixin<T, U>(a: T, b: U): T & U {
  return { ...a, ...b };
}
let p = mixin({ name: 'jw' }, { age: 100 });
let x = mixin(
  { name: 'jiangwen', age: 30, c: 3 },
  { name: 123, age: 30, b: 2 }
);
// 出現交叉類型了,沒有按目標合併,比如保留後面的內容
// 針對這種情況,應用將B有的屬性在A中的移除
function mixin2<T, U>(a: T, b: U): Omit<T, keyof U> & U {
  return { ...a, ...b };
}
let y = mixin2(
  { name: 'jiangwen', age: 30, c: 3 },
  { name: 123, age: 30, b: 2 }
);

type nameType = (typeof y)['name'];

// 保想要key-->value 的結構 一些映射類型
type Record<K extends keyof any, T> = {
  [P in K]: T;
};
type R19 = Record<'a' | 'b', string>; // { a: string; b: string }

export {};

兼容性

// 鴨子類型檢測,結構化類型檢測
// 子類型可以賦予給父類型,從結構角度出發 ts比較的不是類型的名稱,而這個結構上的屬性和方法
// 基礎類型的兼容性
let obj = {
  toString: () => '123',
};
let str: string = '234';

obj = str; // 從安全的角度,你要的屬性我都滿足 有其它屬性,我就不兼容了
// 2. 接口兼容性
interface Person {
  name: string;
  age: number;
}
interface Animal {
  name: string;
  age: number;
  address: string;
}
let p: Person = { name: 'jw', age: 100 };
let a: Animal = { name: 'jw', age: 100, address: 'beijing' };

p = a; // 從安全的角度,你要的屬性我都滿足 有其它屬性,我就不兼容了
// 3. 函數兼容性
type Func = (a: number, b: number) => void;
let f1: Func = (a, b) => {};
let f2: Func = (a, b) => {}; //參數只能少,不能多 (比如我們使用forEach

f1 = f2; // 從安全的角度,你要的參數我都滿足 有其它參數,我就不兼容了

// 4. 類兼容性
class A {
  constructor(public name: string) {}
}
class B {
  constructor(public name: string, public age: number) {}
}
let a1 = new A('jw');
let b1 = new B('jw', 100);

a1 = b1; // 從安全的角度,你要的屬性我都滿足 有其它屬性,我就不兼容了

// 函數的逆變與協變 函數的參數是逆變,返回值是協變
class Parent {
  house() {}
}
class Child extends Parent {
  car() {
    console.log('child car');
  }
}
class GrandSon extends Child {
  money() {
    console.log('grandson money');
  }
}

function fn(callback: (instance: Child) => Childe) {
  let child = new Child();
  let ins = callback(child);
  return ins;
}
// 為甚麼賦予的函數,可以寫Parent類型,但不能寫GrandSon類型, 內部調用的時候傳遞的是Child類型,在拿到這個實例時不能訪問Child訪問不到的屬性
fn((instance: Child) => {
  return new Child();
});

// 返回值應該返回值類型的子類型(分別在不同的角度看)
fn((instance: Child) => {
  return new GrandSon();
});
// 對於函數的兼容性而言,參數個數要少,傳遞可以是父類,返回值可以返回兒子
// 推導公式
type Arg<T> = (arg: T) => void;
type Return<T> = (arg: any) => T;
type ArgType = Arg<Parent> extends Arg<Child> ? true : false; // 逆變
type ReturnType = Return<GrandSon> extends Return<Child> ? true : false; // 協變

// 所以函數的參數是逆變,返回值是協變,

// 枚舉是不具備的兼容性的
// ts比較類型結構時,比較的是屬性和方法,如果屬性和方法都滿足,那麼就具備兼容性

// 通過交叉類型,實現標稱類型
type Normal<T, K extends string> = T & { __type__: K };
type BTC = Normal<number, 'BTC'>;
type ETH = Normal<number, 'ETH'>;
type USDT = Normal<number, 'USDT'>;

let btc: BTC = 100 as BTC;
let eth: ETH = 200 as ETH;
let usdt: USDT = 300 as USDT;

function getVal(val: BTC) {
  return val.valueOf();
}

getVal(btc); //傳其它就報錯了

export {};

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4410

(0)
Walker的頭像Walker
上一篇 2025年11月25日 05:00
下一篇 2025年11月25日 03:00

相關推薦

  • TS珠峰 003【學習筆記】

    裝飾器 // 裝飾器 // 只能在類中使用(類本身,類成員使用) // 裝飾器,類的裝飾器,屬性裝飾器,訪問裝飾器 參數裝飾器 // 1. 類型裝飾器 給類進行擴展,也可以返回一個子類 // 先要在tsconfig.json中開啓experimentalDecorators const classDecorator1 = <T extends new …

    個人 2025年3月27日
    1.5K00
  • Go工程師體系課 004【學習筆記】

    需求分析 後台管理系統 商品管理 商品列表 商品分類 品牌管理 品牌分類 訂單管理 訂單列表 用戶信息管理 用戶列表 用戶地址 用戶留言 輪播圖管理 電商系統 登錄頁面 首頁 商品搜索 商品分類導航 輪播圖展示 推薦商品展示 商品詳情頁 商品圖片展示 商品描述 商品規格選擇 加入購物車 購物車 商品列表 數量調整 刪除商品 結算功能 用戶中心 訂單中心 我的…

    2025年11月25日
    30900
  • 深入理解ES6 001【學習筆記】

    塊級作用域綁定 之前的變量聲明var無論在哪裡聲明的都被認為是作域頂部聲明的,由於函數是一等公民,所以順序一般是function 函數名()、var 變量。 塊級聲明 塊級聲明用於聲明在指定塊的作用域之外無法訪問的變量。塊級作用域存在於: 函數內部 塊中(字符和{和}之間的區域) 臨時死區 javascript引擎在掃描代碼發現變量聲明時,要麼將它們提升至作…

    個人 2025年3月8日
    1.9K00
  • Node深入淺出(聖思園教育) 001【學習筆記】

    node 從異步編程範式理解 Node.js Node.js 的定位與核心思想 基於 V8 引擎 + libuv 事件驅動庫,將 JavaScript 從瀏覽器帶到服務器側。 採用單線程事件循環處理 I/O,最大化利用 CPU 等待 I/O 的時間片,特別適合高併發、I/O 密集型場景。 “不要阻塞主線程”是設計哲學:盡量把耗時操作交給內核或線程池,回調結果…

    個人 2025年11月24日
    40600
  • Go工程師體系課 017【學習筆記】

    限流、熔斷與降級入門(含 Sentinel 實戰) 結合課件第 3 章(3-1 ~ 3-9)的視頻要點,整理一套面向初學者的服務保護指南,幫助理解“為甚麼需要限流、熔斷和降級”,以及如何用 Sentinel 快速上手。 學習路線速覽 3-1 理解服務雪崩與限流、熔斷、降級的背景 3-2 Sentinel 與 Hystrix 對比,明確技術選型 3-3 Sen…

    個人 2025年11月25日
    28000
簡體中文 繁體中文 English