introduction
Continuing with the previous article: [easy part]https:///javascript/
After getting familiar with the basic knowledge points, the middle is smoother overall, but there are too many questions, and it is more about checking for missing and filling in the gaps in knowledge points.
middle part
type MyReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : never; // Implement Omittype Exclude<T, K> = T extends K ? never : T; type MyOmit<T, K extends keyof T> = {[k in Exclude<keyof T, K>]: T[k]} // Specify the part readonly, here assuming that MyOmit has been implemented..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 related, first implement Space typetype 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
This content is still not well-known [distribution condition type], so you can refer to another articledocument.
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 }
There are two difficulties here:
How to make it report an error when repeated assignment
const result2 = a .option('name', 'another name') // @ts-expect-error .option('name', 'last name') .get()
- Give
name
After the attribute is assigned, the value is assigned againname
The attribute will report an error, butts type
Can't use it directlyNoMost people can only use itSupplementMake a judgment - Parameter side
option<P extends string, Q>
It is definitely impossible to use conditional statements to make judgments, if written like thisoption<P extends (P extends keyof T ? never : P), Q>
, will directly report an error <span style="color: red">Type parameter 'P' has a circular constraint.</span> - therefore,Only judge in the function parameters,
option<P extends string, Q>(key: P extends keyof T ? never : P, value: Q)
-
Newly added properties need to be implemented similar
Assign
Method- Can't be used here
Method implementation, original
The implementation method is as follows
assign<T extends {}, U>(target: T, source: U): T & U;
- This implementation brings a problem, i.e.
const b = (aa, { name: 11 });
,typeof b
The result is{ name: string;} & { name: number;}
, obviously does not meet the needs, so I realize it myself 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)}
- Can't be used here
PromiseAll
// Final answerdeclare function PromiseAll<A extends any[]>(values: readonly [...A]): Promise<{ [key in keyof A]: Awaited<A[key]> }>
If you spell this question slowly according to the test cases, it will not be too difficult. The first pieced together is as follows:
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>>;
Two problems were encountered here:
-
PromiseAll<T extends any[]>(values: readonly [...T])
Why do you need to use readonly here- One of the test cases is like this
PromiseAll([1, 2, (3)] as const)
- Didn't check it myself
as const
What does it mean? I asked chat-gpt and the answer I gave is hereas const
It is to turn the data into read-only, which is very clear.readonly
ofT
noT
We want to subclassvalues
Promoted toreadonly
Types of
- One of the test cases is like this
Is it possible to represent an array using an object?
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!!!
- This way of copying objects can be used on arrays
MyCapitalize
I didn't think much about this question at the beginning, and I wrote the correct answer directly
type MyCapitalize<S extends string> = S extends `${infer H}${infer T}` ? `${Uppercase<H>}${T}` : S;
But I thought of a question back,infer H
Why only the first letter is matched, it is greedy,infer
Don't have it?
No relevant article was found online, so I asked chat-gpt, and it told me seriouslyinfer H
The syntax of this format can only match one letter and gives me the following example
type Substring2<S extends string> = S extends `${infer A}${infer _}${infer B}` ? `${A}${B}` : never; type Test = Substring2<'hello'>; // chat-gptSay the result is'hl',Actually running is'hllo'
Several more examples have been tested, such as
type UpperFirstPart<S extends string> = S extends `${infer H} ${infer T}` ? `${Uppercase<H>} ${T}` : S; type Test = UpperFirstPart<"hello world">; // HELLO world
Discoverinfer
WillThe first matching pattern found is the standard,similarMethod, in this way, understand
MyCapitalize
It's much easier to implement
The above is the detailed content of the analysis of the sample analysis of the type challenge (middle part). For more information about type challenge middle, please pay attention to my other related articles!