首页 > 其他分享 >Typescript类型体操 - LastIndexOf

Typescript类型体操 - LastIndexOf

时间:2022-11-12 01:55:13浏览次数:99  
标签:Typescript LastIndexOf true extends 体操 类型 type any

题目

中文

实现类型的 Array.lastIndexOf, LastIndexOf<T, U> 接受泛型参数 Array T 和 any U 并返回数组 T 中最后一个 U 的索引

示例:

type Res1 = LastIndexOf<[1, 2, 3, 2, 1], 2>; // 3
type Res2 = LastIndexOf<[0, 0, 0], 2>; // -1

English

Implement the type version of Array.lastIndexOf, LastIndexOf<T, U> takes an Array T, any U and returns the index of the last U in Array T

For example:

type Res1 = LastIndexOf<[1, 2, 3, 2, 1], 2>; // 3
type Res2 = LastIndexOf<[0, 0, 0], 2>; // -1

答案

type LastIndexOf<T extends any[], U> = T extends [...infer L, infer R]
    ? (<F>() => F extends R ? 1 : 0) extends <F>() => F extends U ? 1 : 0
        ? L['length']
        : LastIndexOf<L, U>
    : -1;

此题与5153 - IndexOf 同源, 重点在于比较两个类型是否一致, github 上 #27024 中探讨了这个问题, 核心就是判断两个类型 X Y 是否完全相同

我最开始想到的做法:

type EqualTo<X, Y> = [X] extends [Y] ? ([Y] extends [X] ? true : false) : false;

这种方法显然有大问题, 比如输入 any1, 期望的结果是 false,实际结果确是 true

然后看到的一个比较容易理解的做法:

type EqualTo<X, Y> = [X extends Y ? 1 : 0, Y extends X ? 1 : 0] ? [1, 1]

然后这个写法能处理 99% 的场景了, 但是如果输入的是 anyunknown, 那么实际会返回 true, 与期望的 false 不符, 这是为什么呢? 因为根据 typescript 的官方文档, 任何一个类型都可以赋值给 unknown (包括 any), 而 unknown 只能赋值给它本身和 any 类型的变量, 所以 any extends unknown ? 1 : 0unknown extends any ? 1 : 0 返回结果相同都是 1, 那么自然 [any extends unknown ? 1 : 0, unknown extends any ? 1 : 0] extends [1, 1] 就是 true 了.

最后经过一番搜索发现了下面这种写法:

type EqualTo<X, Y> = (<F>() => F extends X ? 1 : 0) extends <F>() => F extends Y ? 1 : 0

这种写法下 anyunknown 输入的情况的终于也能正常返回期望的 false. 那为什么这样写有用呢? 在 github issue#27024 看到的解释:

AFAIK it relies on conditional types being deferred when T is not known. Assignability of deferred conditional types relies on an internal isTypeIdenticalTo check, which is only true for two conditional types if:

  • Both conditional types have the same constraint
  • The true and false branches of both conditions are the same type

这段话的意思大概是:

这段代码起作用主要依靠 F 类型未知时存在延迟的条件类型(上面的 F extends X ? 1 : 0); 延迟条件类型的 可转让性(Assignability) 依赖于一个内部的 isTypeIdenticalTo 方法进行检查, isTypeIdenticalTo 只在两个条件类型满足下面的条件时才反会 true

  • 两个条件类型都有相同的约束
  • 两个条件类型在 truefalse 分支下都是相同的类型

两个条件类型在 truefalse 分支下都是相同的类型

理解下这句话, 从这句话能看出, type EqualTo<X, Y> = (<F>() => F extends X ? 1 : 0) extends <F>() => F extends Y ? 1 : 0, 只有 X 与 Y 是同类型, 才能判定 F extends X ? 1 : 0 (这就是上面解释中所谓的条件类型) 与 F extends Y ? 1 : 0 是兼容的

在线演示

标签:Typescript,LastIndexOf,true,extends,体操,类型,type,any
From: https://www.cnblogs.com/laggage/p/type-challenge-last-index-of.html

相关文章

  • 【TS】1103- 30个小知识让你更清楚TypeScript
    TypeScript是Microsoft开发的JavaScript的开源超集,用于在不破坏现有程序的情况下添加附加功能。由于其独特的优势,例如,静态类型和许多速记符号,TypeScript现在被前端和......
  • [Typescript] Zod in actions
    import{z}from"zod";exportenumSUBTYPE{ABORT="abort",START="start",UPLOAD="upload",LOADING="loading",}exportconstTYPE="print"......
  • typescript装饰器
    属性装饰器参数exportdefaultfunction(proto,key){//两个参数}给属性增加metadataimport'reflect-metadata';exportdefaultfunction(label,type?......
  • [Typescript] 97. Hard - Capitalize Words
    Implement CapitalizeWords<T> whichconvertsthefirstletterof eachwordofastring touppercaseandleavestherestas-is.Forexampletypecapitalized......
  • 安装 TypeScript 并编译成JS
    官网:https://github.com/microsoft/TypeScriptTypeScript是一种由微软开发的开源、跨平台的编程语言。它是JavaScript的超集,最终会被编译为JavaScript代码。TypeScript......
  • OJ中Typescript语法整理
    基础原始类型原始类型:number/string/boolean/null/undefined/symbol对象类型:oject(数组,对象,函数等)自定义复杂的对象类型:typeCustomArray=(number|string)let......
  • [Typescript] 95. Hard - Required Keys
    Implementtheadvancedutiltype RequiredKeys<T>,whichpicksalltherequiredkeysintoaunion.ForexampletypeResult=RequiredKeys<{foo:number;bar?:......
  • [Typescript] 96. Hard - Optional Keys
    Implementtheadvancedutiltype OptionalKeys<T>,whichpicksalltheoptionalkeysintoaunion. /*_____________YourCodeHere_____________*/typeOp......
  • typescript 泛型
    一、泛型与any类型的区别泛型是等待确定的占位类型,可以理解为函数的形参;所以泛型是固定的某一个类型,实例化的时候确定其实际类型any类型是顶级类型,它包括了所有的基......
  • [Typescript] 93. Hard - Get Required
    Implementtheadvancedutiltype GetRequired<T>,whichremainsalltherequiredfieldsForexampletypeI=GetRequired<{foo:number,bar?:string}>//exp......