引言
续接上篇:[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
是将数据变为只读,这样的话很明确了,readonly
的t
不是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的资料请关注代码网其它相关文章!
发表评论