最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

typescript中的extends和infer使用及詳解

 更新時(shí)間:2026年04月02日 10:44:02   作者:Young soul2  
文章解釋了TypeScript中的約束、逆變、協(xié)變、交叉類型、可選鏈等概念,通過實(shí)例展示了infer、extends、as等關(guān)鍵字的使用方法,并列舉了加法、減法、乘法、除法、數(shù)組長(zhǎng)度判斷等示例,最后總結(jié)了TypeScript的使用經(jīng)驗(yàn)

extends

extend的意思如果不是用在類的擴(kuò)展中那么就表示約束在

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

比如下面這個(gè)例子:

在Picks中K應(yīng)該約束在keyof T這個(gè)類型中。

infer

infer表示占位符

逆變和協(xié)變

  • 協(xié)變:子類型賦給父類型
  • 逆變:父類型賦給子類型(設(shè)置strictFunctionTypes:true)
  • 雙向協(xié)變:父類型可以賦給子類型,子類型也可以賦給父類型

{}、Object和object

  • {} 是個(gè)空對(duì)象,沒有索引,如果將某些內(nèi)容注釋為{},則可以是任何一種類型。
  • object 不能接收原始類型,而 {} 和 Object 都可以,這是它們的區(qū)別。
  • object 一般會(huì)用 Record<string, any> 代替,約束索引類型更加語義化

&交叉類型

合并兩個(gè)類型

interface IPerson {
  id: string;
  age: number;
}

interface IWorker {
  companyId: string;
}

type IStaff = IPerson & IWorker;

const staff: IStaff = {
  id: 'E1006',
  age: 33,
  companyId: 'EXE'
};

console.dir(staff)

如果是非對(duì)象:

type res = 1 & string

此時(shí)合并的是never,所以非對(duì)象類型合并的必須是同類型

??和?可選鏈

??表示不為null并且不為undefined

const data = {
    name:1
}
const dong = data.name ?? 'dog';
// 編譯后
"use strict";
var _a;
const data = {
    name: 1
};
const dog = (_a = data.name) !== null && _a !== void 0 ? _a : 'dog';

可以看到是表示不為null和undefined才會(huì)獲取data.name否則是’dog’。

?表示為null或者是undefined和??剛好相反

const data = {
    name:1
}
const dong = data?.name;
// 編譯后
"use strict";
const data = {
    name: 1
};
const dong = data === null || data === void 0 ? void 0 : data.name;

可以看到?首先判斷是不是null或者undefined,如果是則返回undefined,否則返回data.name。

keyof any

infer和extends

  • infer只能在extends關(guān)鍵字為true的一側(cè)
  • infer x可以理解成一個(gè)未知數(shù)x,表示待推斷的函數(shù)參數(shù)
type Test<T> = T extends (infer X)[] ? X : never;
// a類型為number | string
let a: Test<number[] | string[]> = '10'

接下來帶大家分析一個(gè)比較好的例子:

type ParseQueryString<Str extends string>
  = Str extends `${infer Param}&${infer Rest}`
  // Param--a=1  Rest--b=2&c=3 // { a:1 }
  ? MergeParams<ParseParam<Param>, ParseQueryString<Rest>>
  : ParseParam<Str>;

// 將a=1這種格式解析為對(duì)象{a:1}
type ParseParam<Param extends string> =
  // a=1  Key--a  Value--1 // { a:1 }
  Param extends `${infer Key}=${infer Value}`
  ? {
    [K in Key]: Value
  } : Record<string, any>;

// {a:1} {b:2,c:3} 用所有的key做對(duì)象,如果只是在其中一個(gè)對(duì)象那么就直接返回,否則合并兩個(gè)對(duì)象的值
type MergeParams<
  OneParam extends Record<string, any>,
  OtherParam extends Record<string, any>
> = {
    // ['a','b','c']
    readonly [Key in keyof OneParam | keyof OtherParam]:
    // 'a' 約束在{a:1}
    Key extends keyof OneParam
    // 'a'是否約束在{b:2,c:3}
    ?
    (Key extends keyof OtherParam
      // 如果'a'同時(shí)約束在{a:1}和{b:2,c:3}那么就合并值返回一個(gè)列表
      ? MergeValues<OneParam[Key], OtherParam[Key]>
      // 否則返回{a:1}中的1
      : OneParam[Key])
    :
    // 'a'是否約束在{b:2,c:3}中,在就取出值否則不返回
    (Key extends keyof OtherParam
      ? OtherParam[Key]
      : never)
  }


type MergeValues<One, Other> =
  // 兩個(gè)一樣
  One extends Other
  ? One
  // other是個(gè)列表
  : Other extends unknown[]
  // 合并列表
  ? [One, ...Other]
  // 直接返回一個(gè)列表
  : [One, Other];


function parseQueryString<Str extends string>(queryStr: Str): ParseQueryString<Str> {
  if (!queryStr || !queryStr.length) {
    return {} as any;
  }
  const items = queryStr.split('&');
  const queryObj: any = {};
  items.forEach(item => {
    const [key, value] = item.split('=');
    if (queryObj[key]) {
      if (Array.isArray(queryObj[key])) {
        queryObj[key].push(value);
      } else {
        queryObj[key] = [queryObj[key], value]
      }
    } else {
      queryObj[key] = value;
    }
  });
  return queryObj
}

const res = parseQueryString('a=1&b=2&c=3')
console.log(res);

使用infer實(shí)現(xiàn)遞歸:

type ReverseStr<
  Str extends string,
  Result extends string = ''
> = Str extends `${infer First}${infer Rest}`
  ? ReverseStr<Rest, `${First}${Result}`>
  : Result;

const a = 'hello'
type b = ReverseStr<typeof a>

/*
Str = hello Result = '' First = h Rest = ello
Str = ello Result = 'h' First = e Rest = llo
Str = llo Result = 'eh' First = l Rest = lo
Str = lo Result = 'leh' First = l Rest = o
Str = o Result = 'lleh' First = o Rest = ''
Str = '' Result = 'olleh' First = '' Rest = ''
 */

下面我們來看看綜合案例:

加法

type BuildArray<
  Length extends number,
  Ele = unknown,
  Arr extends unknown[] = []
> = Arr['length'] extends Length
  ? Arr
  : BuildArray<Length, Ele, [...Arr, Ele]>;

type Add<Num1 extends number, Num2 extends number> =
  [...BuildArray<Num1>, ...BuildArray<Num2>]['length'];

type addResult = BuildArray<10>

減法

type Subtract<Num1 extends number, Num2 extends number> = 
// 模式匹配占取部分值
    BuildArray<Num1> extends [...arr1: BuildArray<Num2>, ...arr2: infer Rest]
        ? Rest['length']
        : never;
type dResult = Subtract<10,9>

乘法

type Mutiply<
    Num1 extends number,
    Num2 extends number,
    ResultArr extends unknown[] = []
> = Num2 extends 0 ? ResultArr['length']
        : Mutiply<Num1, Subtract<Num2, 1>, [...BuildArray<Num1>, ...ResultArr]>;

type mResult = Mutiply<11,10>

除法

type Divide<
    Num1 extends number,
    Num2 extends number,
    CountArr extends unknown[] = []
> = Num1 extends 0 ? CountArr['length']
        : Divide<Subtract<Num1, Num2>, Num2, [unknown, ...CountArr]>;

數(shù)組長(zhǎng)度

type StrLen<
    Str extends string,
    CountArr extends unknown[] = []
> = Str extends `${string}${infer Rest}` 
    ? StrLen<Rest, [...CountArr, unknown]> 
    : CountArr['length']

大于

type GreaterThan<
    Num1 extends number,
    Num2 extends number,
    CountArr extends unknown[] = []
    // 是否相等
> = Num1 extends Num2 
    ? false
    // CountArr長(zhǎng)度是否等于Num2
    : CountArr['length'] extends Num2
        ? true
        // CountArr長(zhǎng)度是否等于Num1
        : CountArr['length'] extends Num1
            ? false
            // 不斷的加1去判斷是否和Num1或者Num2相等,如果先和Num2相等,那就說明Num1是大于Num2的
            : GreaterThan<Num1, Num2, [...CountArr, unknown]>;

過濾

type FilterString<T> = {
  [Key in keyof T as T[Key] extends string ? Key: never]: T[Key];
}

as表示重命名,返回 never 代表過濾掉,否則保留。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • JS實(shí)現(xiàn)的貪吃蛇游戲完整實(shí)例

    JS實(shí)現(xiàn)的貪吃蛇游戲完整實(shí)例

    這篇文章主要介紹了JS實(shí)現(xiàn)的貪吃蛇游戲,結(jié)合完整實(shí)例形式分析了javascript實(shí)現(xiàn)貪吃蛇游戲的具體步驟、原理與相關(guān)操作技巧,需要的朋友可以參考下
    2019-01-01
  • javascript實(shí)現(xiàn)點(diǎn)擊圖片切換

    javascript實(shí)現(xiàn)點(diǎn)擊圖片切換

    這篇文章主要介紹了javascript實(shí)現(xiàn)點(diǎn)擊圖片切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • typescript返回值類型和參數(shù)類型的具體使用

    typescript返回值類型和參數(shù)類型的具體使用

    本文主要介紹了typescript返回值類型和參數(shù)類型的具體使用文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • JS中的回調(diào)函數(shù)實(shí)例淺析

    JS中的回調(diào)函數(shù)實(shí)例淺析

    這篇文章主要介紹了JS中的回調(diào)函數(shù),結(jié)合實(shí)例形式簡(jiǎn)單分析了javascript回調(diào)函數(shù)的感念、功能、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2018-03-03
  • 微信小程序動(dòng)態(tài)顯示項(xiàng)目倒計(jì)時(shí)

    微信小程序動(dòng)態(tài)顯示項(xiàng)目倒計(jì)時(shí)

    這篇文章主要為大家詳細(xì)介紹了微信小程序動(dòng)態(tài)顯示項(xiàng)目倒計(jì)時(shí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • tbody元素支持嵌套的注意方法

    tbody元素支持嵌套的注意方法

    tbody元素支持嵌套的注意方法...
    2007-03-03
  • uniapp小程序?qū)崙?zhàn)之利用騰訊地圖獲取定位

    uniapp小程序?qū)崙?zhàn)之利用騰訊地圖獲取定位

    使用uniapp是因?yàn)樗且粋€(gè)使用vue.js開發(fā)所有前端應(yīng)用的框架,開發(fā)者編寫一套代碼,可以發(fā)布到ios,android,web以及各種小程序,快應(yīng)用等多個(gè)平臺(tái),下面這篇文章主要給大家介紹了關(guān)于uniapp小程序?qū)崙?zhàn)之利用騰訊地圖獲取定位的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • javascript encodeURI和encodeURIComponent的比較

    javascript encodeURI和encodeURIComponent的比較

    在進(jìn)行SaaS前端開發(fā)的時(shí)候,大家經(jīng)常會(huì)用到兩個(gè)JavaScriptNative函數(shù):encodeURI 和 encodeURIComponent。這篇文章詳細(xì)解釋這兩個(gè)函數(shù)的用途并比較它們的不同之處
    2010-04-04
  • js中string轉(zhuǎn)int把String類型轉(zhuǎn)化成int類型

    js中string轉(zhuǎn)int把String類型轉(zhuǎn)化成int類型

    今天碰到一個(gè)問題,需要把String類型的變量轉(zhuǎn)化成int類型的,js中String轉(zhuǎn)int和Java中不一樣,不能直接把Java中的用到j(luò)s中
    2014-08-08
  • JS中some和every的區(qū)別和用法詳解

    JS中some和every的區(qū)別和用法詳解

    every?和?some?都是數(shù)組迭代方法,都可以遍歷數(shù)組,這篇文章主要介紹了JS中some和every的區(qū)別和用法,需要的朋友可以參考下
    2023-05-05

最新評(píng)論

苍山县| 综艺| 台前县| 靖宇县| 河东区| 三门峡市| 视频| 卓尼县| 万山特区| 耒阳市| 简阳市| 宣武区| 吉隆县| 揭阳市| 蛟河市| 天峨县| 崇左市| 上思县| 泸州市| 都兰县| 石门县| 双流县| 奇台县| 安泽县| 乡城县| 湛江市| 精河县| 汉中市| 长治市| 三河市| 饶阳县| 蓝山县| 沙坪坝区| 比如县| 基隆市| 科尔| 临沧市| 垦利县| 沈阳市| 新野县| 南郑县|