{"componentChunkName":"component---src-templates-post-js","path":"/blog/posts/my-favourite-helper-types-in-typescript/","result":{"data":{"header":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMCBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHjiagKm0wchP/EABwQAAMAAQUAAAAAAAAAAAAAAAECAwAQEhMxQf/aAAgBAQABBQKKclKrtbJsFNCug68z/8QAFREBAQAAAAAAAAAAAAAAAAAAIEH/2gAIAQMBAT8Bg//EABURAQEAAAAAAAAAAAAAAAAAACBB/9oACAECAQE/AaP/xAAcEAACAgIDAAAAAAAAAAAAAAABEQACECEgMWH/2gAIAQEABj8CFeomCPMbq5qq4//EABsQAQABBQEAAAAAAAAAAAAAAAEAEBEhMUFR/9oACAEBAAE/IcuA6sv44DQgdOMbXvc0Gk9U/9oADAMBAAIAAwAAABDb537/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPxACCf/EABYRAAMAAAAAAAAAAAAAAAAAAAERIP/aAAgBAgEBPxBmH//EAB0QAQABBAMBAAAAAAAAAAAAAAERABAxQSFRYaH/2gAIAQEAAT8QndiXQAmg3lAIlj6FYCpD3QEJaJ+OLB4RUEYcpm3/2Q==","aspectRatio":1,"src":"/static/5a125f11859148d0d0aadc1049ac37f7/82bc5/photo_2020-01-05_20-24-37.jpg","srcSet":"/static/5a125f11859148d0d0aadc1049ac37f7/b736e/photo_2020-01-05_20-24-37.jpg 25w,\n/static/5a125f11859148d0d0aadc1049ac37f7/b2767/photo_2020-01-05_20-24-37.jpg 50w,\n/static/5a125f11859148d0d0aadc1049ac37f7/82bc5/photo_2020-01-05_20-24-37.jpg 100w,\n/static/5a125f11859148d0d0aadc1049ac37f7/decd9/photo_2020-01-05_20-24-37.jpg 150w,\n/static/5a125f11859148d0d0aadc1049ac37f7/3dcee/photo_2020-01-05_20-24-37.jpg 200w,\n/static/5a125f11859148d0d0aadc1049ac37f7/883ec/photo_2020-01-05_20-24-37.jpg 640w","srcWebp":"/static/5a125f11859148d0d0aadc1049ac37f7/4226e/photo_2020-01-05_20-24-37.webp","srcSetWebp":"/static/5a125f11859148d0d0aadc1049ac37f7/12e7b/photo_2020-01-05_20-24-37.webp 25w,\n/static/5a125f11859148d0d0aadc1049ac37f7/ecb58/photo_2020-01-05_20-24-37.webp 50w,\n/static/5a125f11859148d0d0aadc1049ac37f7/4226e/photo_2020-01-05_20-24-37.webp 100w,\n/static/5a125f11859148d0d0aadc1049ac37f7/e8bcc/photo_2020-01-05_20-24-37.webp 150w,\n/static/5a125f11859148d0d0aadc1049ac37f7/1c9b5/photo_2020-01-05_20-24-37.webp 200w,\n/static/5a125f11859148d0d0aadc1049ac37f7/2420f/photo_2020-01-05_20-24-37.webp 640w","sizes":"(max-width: 100px) 100vw, 100px","presentationWidth":100}}},"page":{"fields":{"url":"/blog/posts/my-favourite-helper-types-in-typescript/"},"frontmatter":{"title":"My Favourite Helper Types in Typescript","subtitle":"Some handy utility types that I keep coming back to","keywords":[],"template":"post","canonical_url":"","noindex":null,"date":"2021-01-27T19:00:00.000Z","tweet":null,"github":null,"content_img_path":{"childImageSharp":{"fluid":{"tracedSVG":"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='450'%20height='300'%20viewBox='0%200%20450%20300'%20preserveAspectRatio='none'%3e%3cpath%20d='M0%20150v150h451V0H0v150m230-37c-8%202-12%207-12%2015%200%206%202%2010%2012%2015%209%206%2012%209%2012%2013%200%209-11%2012-21%206l-4-2v4c0%205%201%206%2010%207%207%200%2013-1%2017-5%203-2%203-3%204-9%200-7%200-7-3-11l-10-7c-9-5-11-7-11-12%200-8%2010-11%2020-7%202%201%203-5%201-6-3-1-10-2-15-1m-163%203l-1%203h8l9%201v50h6v-25l1-25%208-1h8v-5l-20-1H67v3m302%203c-2%200-2%201-2%205v6l-4-1c-3%200-3%200-3%203s0%203%204%203h3v14l1%2017c4%206%2015%207%2015%201%200-2%200-2-3-2-6%200-7-2-7-17v-13h5c5%200%205%200%205-3s0-3-5-3l-4%201-1-6-1-6-3%201M94%20132l8%2020%207%2018-2%205c-3%206-5%208-9%208-3%200-3%200-3%203s0%203%203%203c4%200%209-3%2012-6l21-53-3-1c-3%200-4%201-5%204l-6%2017-5%2013-4-13c-8-22-7-20-11-21-3%200-3%200-3%203m42-2v58h6v-23l2%202c6%204%2011%205%2018%202%2012-6%2014-31%203-38-7-4-20-2-22%204%200%201-1%201-1-2s-4-5-6-3m50%201c-13%208-13%2031%201%2038%208%204%2022%201%2022-5v-3l-4%202c-9%204-18%202-21-5-2-7-2-7%2014-7h14v-5c-2-11-7-17-17-17l-9%202m79-1c-14%207-16%2029-4%2038%208%205%2021%203%2022-3v-3l-3%201c-10%206-20-1-20-13s9-19%2020-15l3%202v-3c0-3%200-4-2-4h-16m22%2020v20h6v-11c0-18%203-24%2011-24%204%200%204%200%204-3%200-6-9-4-14%204-1%201-1%201-1-3s0-4-3-4h-3v21m26-20l-1%2020v20h6v-20l1-20-3-1-3%201m10%200l-1%2058h7v-23l2%202c6%205%2011%205%2018%202%2012-6%2014-31%203-38-7-4-20-2-22%204%200%201-1%201-1-2s-4-5-6-3m-173%205c-6%202-7%206-8%2015v8l3%203c7%207%2017%204%2020-6%204-13-5-24-15-20m38%202c-3%202-5%207-4%208l11%201c11%200%2011%200%209-7-3-5-11-7-16-2m149-2c-10%204-11%2025-2%2029%206%203%2013%201%2015-5%207-13-2-29-13-24'%20fill='%23d3d3d3'%20fill-rule='evenodd'/%3e%3c/svg%3e","aspectRatio":2.601769911504425,"src":"/static/4a85a073f61d6e9d1c8a3e8e7b9df94d/342e6/typescript-banner.jpg","srcSet":"/static/4a85a073f61d6e9d1c8a3e8e7b9df94d/4aede/typescript-banner.jpg 294w,\n/static/4a85a073f61d6e9d1c8a3e8e7b9df94d/7ae0f/typescript-banner.jpg 585w,\n/static/4a85a073f61d6e9d1c8a3e8e7b9df94d/342e6/typescript-banner.jpg 832w","srcWebp":"/static/4a85a073f61d6e9d1c8a3e8e7b9df94d/65238/typescript-banner.webp","srcSetWebp":"/static/4a85a073f61d6e9d1c8a3e8e7b9df94d/74efb/typescript-banner.webp 294w,\n/static/4a85a073f61d6e9d1c8a3e8e7b9df94d/5da3e/typescript-banner.webp 585w,\n/static/4a85a073f61d6e9d1c8a3e8e7b9df94d/65238/typescript-banner.webp 832w","sizes":"(max-width: 832px) 100vw, 832px","presentationWidth":832}}}}}},"pageContext":{"url":"/blog/posts/my-favourite-helper-types-in-typescript/","relativePath":"blog/posts/my-favourite-helper-types-in-typescript.md","relativeDir":"blog/posts","base":"my-favourite-helper-types-in-typescript.md","name":"my-favourite-helper-types-in-typescript","html":"<p>Over the past few years of using Typescript and slowly getting comfortable writing complex custom types, I have amassed a collection of small helper types from around the internet. Here are a few of them that I end up adding to almost all my major projects and how I use them:</p>\n<h2>Unpromise</h2>\n<p>Sometimes you need to get the resolved value of a <code>Promise&#x3C;T></code> wrapped type, mostly when using along with the inbuilt <a href=\"https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype\" target=\"_blank\" rel=\"noopener noreferrer\"><code>ReturnType</code></a> type:</p>\n<pre><code class=\"language-ts\">type Unpromise&#x3C;T> = T extends Promise&#x3C;infer U> ? U : T;\n\ntype a = Promise&#x3C;number>;\ntype x = Unpromise&#x3C;a>; // number\n</code></pre>\n<p>Use with <code>ReturnType</code> to make <code>ReturnTypeResolved</code>:</p>\n<pre><code class=\"language-ts\">type ReturnTypeResolved&#x3C;T extends (...args: any) => any> = Unpromise&#x3C;\n  ReturnType&#x3C;T>\n>;\n\nfunction test(): Promise&#x3C;{ weird: \"value\" }> {\n  return Promise.resolve({ weird: \"value\" });\n}\n\ntype WeirdType = ReturnTypeResolved&#x3C;typeof test>;\n</code></pre>\n<span class=\"no-border\">\n<p><a href=\"https://www.typescriptlang.org/play?ssl=12&#x26;ssc=37&#x26;pln=12&#x26;pc=43#code/C4TwDgpgBAqgdmATgewLYEsDOEA8AVAPigF4o8oIAPYCOAE0ygAUUNsd04AzCRWIgPywoALjIBuAFCTQkKAEMSzVllxwArqgBGvAlNnRKS+EjSqc8vVAD01qBu29pBqACUIwdYjh5wEd5jIADYAbhB0+BTUtAxQABQAdEnyiADmmGLycCAAlCREWSBEpCYq7O6e3r6Q+AR60lzqcADGwOjIcFA0mMBxOWIsZuwA3gDuEOiIdGIA5CHyQeoQMwC+RMOSUFCIHl6dg2wQCTuBoRBxYxNTs-OLyys5UivOflAA6ld01dCkFXvfAWCYQiBmQXC6EB6eiAA\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"https://img.shields.io/badge/Open_in_Playground-555555.svg?style=flat-square&#x26;logo=typescript&#x26;labelColor=3178c6&#x26;logoColor=fff\" alt=\"Open in TS Playground\"></a></p>\n</span>\n<h2>PlainObject</h2>\n<p>I know we have the inbuilt <a href=\"https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeystype\" target=\"_blank\" rel=\"noopener noreferrer\"><code>Record</code></a> but this is such a common and <strong>frequent</strong> use case that I like having this around:</p>\n<pre><code class=\"language-ts\">type PlainObject&#x3C;T = any> = Record&#x3C;string, T>;\n\ntype NumMap = PlainObject&#x3C;number>;\nconst a: NumMap = {\n  key1: 1,\n  key2: 2,\n  keyx: \"x\", // ERROR: expected number\n};\n</code></pre>\n<p>You can also create a reverse of this, <code>ValueOf&#x3C;T></code>:</p>\n<pre><code class=\"language-ts\">type ValueOf&#x3C;T> = T[keyof T];\n\ntype x = ValueOf&#x3C;NumMap>; // number\n</code></pre>\n<span class=\"no-border\">\n<p><a href=\"https://www.typescriptlang.org/play?#code/C4TwDgpgBACgNgQwJYDsDyAjAVhAxsAHgBUoBeKBFEAPjKgCU8B7AJwBMCBnYF1AcwA0UItQDcAKHGhIUAHIBXALYBZBGDrxk6bHkIolGCCzHjcTFNwoAuOUtXryAb3FQoAawggAjDa8CX7p4ATDZB-q4eIAAeNgDkUbFCAPRJUACi9PRo9DYQUZD4EGxQ+oqGLOIAvhJS4NAAaghw8hBoAGbEtOREANqRTG3CALo10tBRdI3NrR0KKmpiUCklBkbiQA\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"https://img.shields.io/badge/Open_in_Playground-555555.svg?style=flat-square&#x26;logo=typescript&#x26;labelColor=3178c6&#x26;logoColor=fff\" alt=\"Open in TS Playground\"></a></p>\n</span>\n<h2>RecursivePartial</h2>\n<p><a href=\"https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype\" target=\"_blank\" rel=\"noopener noreferrer\"><code>Partial</code></a> but for nested objects, most useful when declaring defaults or merging some overrides for a config type:</p>\n<pre><code class=\"language-ts\">type RecursivePartial&#x3C;T> = {\n  [P in keyof T]?: T[P] extends (infer U)[]\n    ? RecursivePartial&#x3C;U>[]\n    : T[P] extends object\n    ? RecursivePartial&#x3C;T[P]>\n    : T[P];\n};\n\nconst config = {\n  a: {\n    x: {\n      p: 1,\n      q: 2,\n    },\n    y: \"nested\",\n    z: \"value\",\n  },\n  b: \"root\",\n  c: \"value\",\n};\n\nconst configOverride: RecursivePartial&#x3C;typeof config> = {\n  a: {\n    x: {\n      p: \"wrong\", // should be number\n    },\n  },\n};\n</code></pre>\n<span class=\"no-border\">\n<p><a href=\"https://www.typescriptlang.org/play?#code/C4TwDgpgBAShDGBXATgZwJYDcIAUCGyw6eANgDwAqAfFALxQDeAUFFANo5ToB2UA1hBAB7AGZQKAXQD8ALhatxHCVAgAPYBG4ATVFAAUPERGRQAqgEo2yqbAQoM2fIWLlTVK1DkLFOZWo3aukIARgBWCMBQNnBIaFi4BESklEo0XgoUSgDcTAC+OUzwQtyokUXcIugA5nSM8ngydd6qjczerGCNAIwANPLeAI6NAEx93rljCiCNAOTcEKUQWjOTrABes5ikiBAr8hPywbPIQkLAe6zwm9u7fflMhcWlUOWVVQDy2MjI6FoQjTF7PEnElyKBIKIXsU3jR6G0oA0mgoWkjvJ0oDMAO4nbhVFZQAD0BKgqAAFkJECQtFBgtBuIgALa05D9KAHVgHfJAA\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"https://img.shields.io/badge/Open_in_Playground-555555.svg?style=flat-square&#x26;logo=typescript&#x26;labelColor=3178c6&#x26;logoColor=fff\" alt=\"Open in TS Playground\"></a></p>\n</span>\n<h2>Also See</h2>\n<p>Go over the inbuilt utility types in the <a href=\"https://www.typescriptlang.org/docs/handbook/utility-types.html\" target=\"_blank\" rel=\"noopener noreferrer\">Typescript Docs</a>. And checkout this great library, <a href=\"https://github.com/piotrwitek/utility-types\" target=\"_blank\" rel=\"noopener noreferrer\">utility-types</a> on Github for other common types people tend to use.</p>\n<h3>Credits</h3>\n<p>Links to the various places I originally found these from:</p>\n<ul>\n<li><code>Unpromise</code>: Sourced from this StackOverflow Answer: <a href=\"https://stackoverflow.com/a/53196435/9485498\" target=\"_blank\" rel=\"noopener noreferrer\">https://stackoverflow.com/a/53196435/9485498</a></li>\n<li><code>RecursivePartial</code>: Sourced from this StackOverflow Answer: <a href=\"https://stackoverflow.com/a/51365037/9485498\" target=\"_blank\" rel=\"noopener noreferrer\">https://stackoverflow.com/a/51365037/9485498</a></li>\n</ul>","headerImg":"photo_2020-01-05_20-24-37.jpg"}},"staticQueryHashes":["1161966454","1673585186","1866307108","219491723","2948329147","3269044456","629512913"]}