avatarBytefer

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

3808

Abstract

span class="hljs-keyword">in</span> <span class="hljs-type">T</span> required.

  • typescript/lib/lib.es5.d.ts */ <span class="hljs-keyword">type</span> <span class="hljs-type">Required</span><<span class="hljs-type">T</span>> = { [<span class="hljs-type">P</span> in keyof <span class="hljs-type">T</span>]-?: <span class="hljs-type">T</span>[<span class="hljs-type">P</span>]; };</pre></div><p id="fce1">The <code>Required<T></code> generic uses TypeScript’s <b>mapped type</b> internally, and its syntax is as follows:</p><figure id="00f4"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*7iuvURZie0JxNSmuAQe94w.jpeg"><figcaption></figcaption></figure><p id="5ef8">Where <code>P in K</code> is similar to the JavaScript <code>for...in</code> statement, which is used to iterate through all types in type <code>K</code>, and the type variable <code>T</code>, which is used to represent any type in TypeScript.</p><figure id="29b6"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*YK9f_jV3ETabwSDqHUSCmQ.gif"><figcaption></figcaption></figure><p id="180f">You can also use the additional modifiers read-only and question mark (?) in the mapping process. The corresponding modifiers are added and removed by adding the plus(+) and minus(-) prefixes. <b>The default is to use the plus sign if no prefix is added.</b></p><p id="d251">After introducing the relevant knowledge of <b>mapped types</b>, the idea of ​​​​implementing the <code>RequiredByKeys</code> generic is very simple.</p><figure id="27f2"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*zQVBtpUJZPSays_tK-zcXg.jpeg"><figcaption></figcaption></figure><p id="bb04">As can be seen from the above figure, we only need to select the properties associated with K, set them as required and generate a new object type, then build another object type based on the remaining properties, and finally use the <code>&</code> operator to convert the above two object types are combined into a new object type.</p><p id="783d">If you want to learn more about <b>intersection types</b>, you can read this article.</p><div id="d973" class="link-block"> <a href="https://javascript.plainenglish.io/using-typescript-intersection-types-like-a-pro-a55da6a6a5f7"> <div> <div> <h2>Using TypeScript Intersection Types Like a Pro</h2> <div><h3>Details of what you should know about TypeScript Intersection Types — explained with animations.</h3></div> <div><p>javascript.plainenglish.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*b0EDOgd63mgLUCcnj5sQWQ.jpeg)"></div> </div> </div> </a> </div><h2 id="7db3">Complete code</h2><p id="e2c5">Finally, let’s look at the complete code:</p> <figure id="afd8"> <div> <div>

             <iframe class="gist-iframe" src="/gist/semlinker/b33f05cd095d94c03c5c95748287b9b9.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
           </div>
         </div>
     </figure></iframe></div></div></figure><p id="c52c">TypeScript 4.1 allows us to <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#key-remapping-in-mapped-types"><b>remapping keys</b></a> in mapped types using the as clause. Its syntax is as follows:</p><div id="e2c6"><pre><span class="hljs-keyword">type</span> <span class="hljs-type">MappedTypeWithNewKeys</span>&lt;<span class="hljs-type">T</span>&gt; = {
    

    [<span class="hljs-type">K</span> in keyof <span class="hljs-type">T</span> as <span class="hljs-type">NewKeyType</span>]: <

Options

span class="hljs-type">T</span>[<span class="hljs-type">K</span>] // ^^^^^^^^^^^^^ // <span class="hljs-type">New</span> <span class="hljs-type">Syntax</span>! }</pre></div><p id="0bbb">where the type of the <b>NewKeyType</b> must be a subtype of the <code>string | number | symbol</code> union type. <b>In the process of remapping the keys, we can filter the keys by returning the never type.</b></p><figure id="7b3e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*fj_Ok76xv7a1m1vtlTXJjQ.jpeg"><figcaption></figcaption></figure><p id="28e1">The role of the <code>Merge</code> generic is to merge object types. In addition to the above solutions, there is a more concise way.</p><div id="7887"><pre><span class="hljs-built_in">type</span> RequiredByKeys<<span class="hljs-built_in">T</span>, K = keyof <span class="hljs-built_in">T</span>> = Merge< <span class="hljs-built_in">T</span> & { [P in keyof <span class="hljs-built_in">T</span> as P extends K ? P <span class="hljs-symbol">:</span> never]-?<span class="hljs-symbol">:</span> <span class="hljs-built_in">T</span>[P] } ></pre></div><p id="51b3">The main knowledge involved in this challenge is TypeScript’s <b>mapped types</b>. If you want to learn more about <b>mapped types</b>, you can read the following article:</p><div id="c94d" class="link-block"> <a href="https://javascript.plainenglish.io/using-typescript-mapped-types-like-a-pro-be10aef5511a"> <div> <div> <h2>Using TypeScript Mapped Types Like a Pro</h2> <div><h3>Mapped Types — Explained with animations. Master TypeScript Mapped Types and understand how TypeScript’s built-in…</h3></div> <div><p>javascript.plainenglish.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*FMXS28oOxZLr-MtIjkU2mQ.jpeg)"></div> </div> </div> </a> </div><p id="61b9">If you have other solutions, you can give me a message. you also can follow me on <a href="https://medium.com/@bytefer">Medium</a> or <a href="https://twitter.com/Tbytefer">Twitter</a> to read more about TS and JS!</p><h1 id="fca5">Resources</h1><div id="8278" class="link-block"> <a href="https://github.com/type-challenges/type-challenges/blob/main/questions/02759-medium-requiredbykeys/README.md"> <div> <div> <h2>type-challenges/README.md at main · type-challenges/type-challenges</h2> <div><h3>by jiangshan @jiangshanmeta Implement a generic RequiredByKeys which takes two type argument T and K. K specify the set…</h3></div> <div><p>github.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*_Z5C4yU__UCfrCov)"></div> </div> </div> </a> </div><div id="4788" class="link-block"> <a href="https://readmedium.com/with-these-articles-you-will-not-be-confused-when-learning-typescript-d96a5c99e229"> <div> <div> <h2>With These Articles, You Will Not Be Confused When Learning TypeScript</h2> <div><h3>Through Vivid Animations, You Can Easily Understand the Difficult Points and Core Knowledge of TypeScript! Continuously…</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*f1j_y98p4zYxXGLD-fNvDQ.jpeg)"></div> </div> </div> </a> </div></article></body>

Type Challenges: Implement the RequiredByKeys<T, K> Utility Type

The Built-In Required Generic Are Not Flexible, the RequiredByKeys Generics Come to the Rescue.

Welcome to the Mastering TypeScript series, there are dozens of articles in this series. To help readers better consolidate their knowledge of TypeScript, I have selected a few dozen challenges from the type-challenges repository on Github to complete the type challenge with you.

Challenge

Implement a generic RequiredByKeys<T, K> which takes two type argument T and K.

K specify the set of properties of T that should set to be required. When K is not provided, it should make all properties required just like the normal Required<T>.

For example:

interface User {
  name?: string
  age?: number
  address?: string
}
type UserRequiredName = RequiredByKeys<User, 'name'> 
// { name: string; age?: number; address?: string }

Solution

Our type challenge is to implement the RequiredByKeys<T, K> generic, when K is not provided, it should make all properties required just like the normal Required<T>. So let’s first understand what Required<T> generic does.

Required<T>

Constructs a type consisting of all properties of Type set to required. The opposite of Partial.

Required<T> is TypeScript’s built-in utility type, which is defined in the typescript/lib/lib.es5.d.ts file:

/**
 * Make all properties in T required.
 * typescript/lib/lib.es5.d.ts
 */
type Required<T> = {
    [P in keyof T]-?: T[P];
};

The Required<T> generic uses TypeScript’s mapped type internally, and its syntax is as follows:

Where P in K is similar to the JavaScript for...in statement, which is used to iterate through all types in type K, and the type variable T, which is used to represent any type in TypeScript.

You can also use the additional modifiers read-only and question mark (?) in the mapping process. The corresponding modifiers are added and removed by adding the plus(+) and minus(-) prefixes. The default is to use the plus sign if no prefix is added.

After introducing the relevant knowledge of mapped types, the idea of ​​​​implementing the RequiredByKeys generic is very simple.

As can be seen from the above figure, we only need to select the properties associated with K, set them as required and generate a new object type, then build another object type based on the remaining properties, and finally use the & operator to convert the above two object types are combined into a new object type.

If you want to learn more about intersection types, you can read this article.

Complete code

Finally, let’s look at the complete code:

TypeScript 4.1 allows us to remapping keys in mapped types using the as clause. Its syntax is as follows:

type MappedTypeWithNewKeys<T> = {
    [K in keyof T as NewKeyType]: T[K]
    //            ^^^^^^^^^^^^^
    //            New Syntax!
}

where the type of the NewKeyType must be a subtype of the string | number | symbol union type. In the process of remapping the keys, we can filter the keys by returning the never type.

The role of the Merge generic is to merge object types. In addition to the above solutions, there is a more concise way.

type RequiredByKeys<T, K = keyof T> = Merge<
  T & {
    [P in keyof T as P extends K ? P : never]-?: T[P]
  }
>

The main knowledge involved in this challenge is TypeScript’s mapped types. If you want to learn more about mapped types, you can read the following article:

If you have other solutions, you can give me a message. you also can follow me on Medium or Twitter to read more about TS and JS!

Resources

Typescript
JavaScript
Front End Development
Web Development
Programming
Recommended from ReadMedium