当前位置: 代码网 > it编程>编程语言>Javascript > type challenge刷题之(middle 部分)示例解析

type challenge刷题之(middle 部分)示例解析

2024年05月15日 Javascript 我要评论
引言续接上篇:[easy 部分]熟悉了基本知识点之后,middle整体比较顺畅,就是题目太多,更多是知识点的查漏补缺。middle部分type myreturntype<t extends (.

引言

续接上篇:[easy 部分] 

熟悉了基本知识点之后,middle整体比较顺畅,就是题目太多,更多是知识点的查漏补缺。

middle部分

type myreturntype<t extends (...args: any[]) => any> = 
    t extends (...args: any[]) => infer r ? r : never;
// 实现omit
type exclude<t, k> = t extends k ? never : t;
type myomit<t, k extends keyof t> = {[k in exclude<keyof t, k>]: t[k]}
// 指定部分readonly,此处假设已经实现了myomit..
type myreadonly2<t, k extends keyof t = keyof t> = {readonly [k in k]: t[k]} & myomit<t, k>
type deepreadonly<t> = {
  readonly [p in keyof t]: keyof t[p] extends never ? t[p] : deepreadonly<t[p]>;
};
type tupletounion<t extends any[]> = t[number];
type last<t extends any[]> = t extends [...any[], infer u] ? u : never;
type pop<t extends any[]> = t extends [...infer u, any] ? u : t;
type lookup<u, t> = u extends {type: t} ? u : never;
// trim相关,先实现space类型
type space = ' '|'\n'|'\t';
type trimleft<s extends string> = s extends `${space}${infer u}` ? trimleft<u> : s;
type trim<s extends string> = s extends `${space}${infer u}`|`${infer u}${space}` ? trim<u>: s;
type replace<s extends string, from extends string, to extends string> = from extends '' ? s : (s extends `${infer h}${from}${infer t}` ? `${h}${to}${t}` : s);

deepreadonly

这块内容还是【分配条件类型】没掌握好,可以参看另一篇.

chinable

type myassign<t extends {}, q extends {}> = {[k in (keyof t|keyof q)]: k extends keyof q ? q[k] : (k extends keyof t ? t[k]: undefined)}
type chainable<t extends {} = {}> = {
  option<p extends string, q>(key: p extends keyof t ? never : p, value: q): chainable<myassign<t, record<p, q>>>
  get(): t
}

这里难点有两个:

重复赋值时,怎么让其报错

const result2 = a
    .option('name', 'another name')
    // @ts-expect-error
    .option('name', 'last name')
    .get()
  • name属性赋值后,再次赋值name属性就会报错,但ts type没法直接用判断,大多只能利用其补集进行判断
  • 参数侧option<p extends string, q>肯定是没法用条件语句进行判断,如果这么写option<p extends (p extends keyof t ? never : p), q>,会直接报错<span style="color: red">type parameter 'p' has a circular constraint.</span>
  • 因此,只能在函数的参数中进行判定option<p extends string, q>(key: p extends keyof t ? never : p, value: q)
  • 新添加的属性,需要实现类似assign的方法

    • 这里不能用object.assign方法的实现方式,原本object.assign的实现方式如下
    • assign<t extends {}, u>(target: t, source: u): t & u;
    • 这种实现方式带来了一个问题,即const b = object.assign(aa, { name: 11 });typeof b的结果为{ name: string;} & { name: number;},显然不符合需求,因此自己实现
    • type myassign<t extends {}, q extends {}> = {[k in (keyof t|keyof q)]: k extends keyof q ? q[k] : (k extends keyof t ? t[k]: undefined)}

promiseall

// 最终答案
declare function promiseall<a extends any[]>(values: readonly [...a]): promise<{
  [key in keyof a]: awaited<a[key]>
}>

这一题如果按照测试用例慢慢拼的话,也不算太难,最开始拼凑出来的写法如下:

type promisevalue<t> = t extends promise<infer v> ? promisevalue<v> : t;
type promisevalues<t extends any[], r extends any[] = []> = t extends [infer h, ...infer e] ? promisevalues<e, [...r, promisevalue<h>]>: ([] extends r ? promisevalue<t[number]>[] : r);
declare function promiseall<t extends any[]>(values: readonly [...t]): promise<promisevalues<t>>;

这里遇到了两个问题:

  • promiseall<t extends any[]>(values: readonly [...t])这里为什么要用readonly

    • 其中有个测试用例是这样的promiseall([1, 2, promise.resolve(3)] as const)
    • 自己没查到as const是什么意思,问了chat-gpt,给的答复是这里的as const是将数据变为只读,这样的话很明确了,readonlyt不是t的子类,我们要将values提升为readonly的类型

是否可以用对象表示数组

type a = [number, string, {a: number}]
  type b = {
    [k in keyof a]: a[k]
  }
  type c = a extends b ? (b extends a ? true: false): false; // true!!!
  • 这种复制对象的方式,可以用在数组上

mycapitalize

这一题一开始没想多少,直接写出了正确答案

type mycapitalize<s extends string> = s extends `${infer h}${infer t}` ? `${uppercase<h>}${t}` : s;

但回头想到了一个问题,infer h为什么只匹配了第一个字母,正则具有贪婪性,infer不具备吗?

网上没找到相关文章,问了chat-gpt,它一本正经告诉我infer h这种格式的语法只能匹配一个字母,并给了我下面的例子

type substring2<s extends string> = s extends `${infer a}${infer _}${infer b}` ? `${a}${b}` : never;
type test = substring2<'hello'>; // chat-gpt说结果是'hl',实际跑是'hllo'

多测试了几个例子,诸如

type upperfirstpart<s extends string> = s extends `${infer h} ${infer t}` ? `${uppercase<h>} ${t}` : s;
type test = upperfirstpart<"hello world">; // hello world

发现infer会以第一个找到的匹配模式为标准,类似array.find方法,这样的话,理解mycapitalize的实现就容易多了

以上就是type challenge刷题之(middle 部分)示例解析的详细内容,更多关于type challenge middle的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com