Last active
July 17, 2023 12:22
-
-
Save Kjaer/e39e7046a8f7c920426227857a25eb2d to your computer and use it in GitHub Desktop.
Type narrowing with mapped types. This gist, iterate over nested union types and narrows the type definition for later filtering.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Sitemap = { | |
pageIdentifier?: 'Page'; | |
slug?: string | null; | |
seo?: { pageIdentifier: 'Seo'; noIndex?: boolean | null } | null; | |
content?: | |
| { pageIdentifier?: 'AppHomePage' } | |
| { | |
pageIdentifier: 'CategoryPage'; | |
blockedInCountry?: boolean | null; | |
link?: string | null; | |
published?: boolean | null; | |
globalCanonical?: { pageIdentifier?: 'Page'; slug?: string | null } | null; | |
localizedCanonical?: { pageIdentifier?: 'Page'; slug?: string | null } | null; | |
} | |
| { | |
pageIdentifier: 'ContentPage'; | |
title: string; | |
globalCanonical?: { pageIdentifier?: 'Page'; slug?: string | null } | null; | |
localizedCanonical?: { pageIdentifier?: 'Page'; slug?: string | null } | null; | |
} | |
| { pageIdentifier: 'StartPage' } | |
| { pageIdentifier: 'SystemPage' } | |
| { pageIdentifier: 'WorldHomePage' } | |
| null; | |
}; | |
type CategoryPage = { | |
[Key in keyof Sitemap]: Sitemap[Key] extends Sitemap['content'] | |
? Extract<Sitemap['content'], { pageIdentifier: 'CategoryPage' }> | |
: Sitemap[Key] | |
} | |
type ContentPage = { | |
[Key in keyof Sitemap]: Sitemap[Key] extends Sitemap['content'] | |
? Extract<Sitemap['content'], { pageIdentifier: 'ContentPage' }> | |
: Sitemap[Key] | |
} | |
const isCategoryPageOrContentPage = <Page extends CategoryPage | ContentPage>( | |
item: Sitemap | null, | |
): item is Page => | |
item?.content?.pageIdentifier === 'CategoryPage' || item?.content?.pageIdentifier === 'ContentPage' | |
const item: Sitemap = {} | |
console.log(isCategoryPageOrContentPage<CategoryPage>(item)) // Narrows type of `item` for `content` field is `pageIdentifier: 'CategoryPage'` | |
console.log(isCategoryPageOrContentPage<ContentPage>(item)) // Narrows type of `item` for `content` field is `pageIdentifier: 'ContentPage'` | |
console.log(isCategoryPageOrContentPage<ContentPage | CategoryPage>(item)) // // Narrows type of `item` for `content` field can be either `pageIdentifier: 'CategoryPage'` or `pageIdentifier: 'ContentPage'` | |
function isContentPageItem(item: Sitemap): false | void { | |
//narrows the `content` field type only for `pageIdentifier: 'ContentPage'` | |
if(!isCategoryPageOrContentPage<ContentPage>(item)) { return false } | |
console.log(item.content?.title); | |
} | |
function isCategoryPageItem(item: Sitemap): false | void { | |
//narrows the `content` field type only for `pageIdentifier: 'CategoryPage'` | |
if(!isCategoryPageOrContentPage<CategoryPage>(item)) { return false } | |
console.log(item.content?.published); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Playground link:
https://www.typescriptlang.org/play?ssl=64&ssc=2&pln=1&pc=1#code/C4TwDgpgBAyglsCBbAhmKBeKBvAUFKMFAcwgEkATCAO2DgDM4IAnAfgC4oByABRIi4BufFADOAGwCuxDmODM41YlAA+UapPHjhBURAD2s7IX6UadRi05cYBoev1lqVAB6yARvv3iIKaqvVNcSgAXwCNLR0oAGN9WnMOEQI1YyJSM1oGJjZrAEEwMAAJfSQIPlIuUKSAvAI6urTyKkzLZmsAYRREYn1mEHKBKPqCd3F9aIBrCAondv1JWj6PLx8-cKCh4fFFCdlReUVlNQjtavqwSVG4UQALaeXvX39jjbO64jH3FHFO6ji4aLfIwmdLNCzZWS8fj2CTSPYHJTrLShJGnYZ1MaA7YAL2mv3+WOBjQy4JYkIGMKkMk4+wUiJeyLCDLRwxC1RSbwIxLBWSs3Dm8VoFM29TowB8NIRxBF70+33x1ABQM4qVMPNa5OhgjEVPhdKOgUZqJlBEx3zguIoCqV4iJavMvJy3GFOrhkv1qJRzJlbPqKRBTQdrWsMGAKGYwApVT9OADJMdIZA+2QUd9dX93KD2WsAHVeuIKMVSqn2YbTiFhLhQJAoJ1ur1+vxMDgRABtADSEBAUEUUCmIH09FgCGQaAAupx4IhUGAO12x1AIC5EM5RMPp2hW1xYoLgFwx9VWFAAKLL5goaLAAA8U9Hs+3cRXe7HABpY5mWtn+V0ID0+qmAD5qknEcZznEADzZKtwGgAUnwGZtaigcCe38ftB3XO8J0wsDOwgxdlxoCg11vMCH13fdDxPM8L2vUjN3Ip99zfVVQSzPkuDg8xAOAnDNzwyDcFwHd9h7UQ61-BsBgAeWYLihSbLArwQpcV2I2sfz-RtSACeTI34ACAAoRFAkCN3QZkX1wABKThQLEqAEIwICCFA1gADodyfDyP1JZhMAwLBOM0qToVUNQ3M8x8Enc3zHQCoK9IpISROAHtpzMu9EKgkTHncsZiEM64JK0mS5OihTSCvErQtIIzQOs6yoAAemaqAADlw2YfQAHc12raAMIAA1AoaoHoXooCGrzzDGywCwcoa4uDb963-aEhuEuJRDygqivEkL1tIWSkv4aqKv0uqiunRqWrazrmG6vqoAGqBhtG8bJumi65qYBbrim5av04i6KU23KfHy-RCuKw7tIgE7QbO06dLUGqjogeqbqa1q7o6rrev6mC3qHEbpzmr6ZtoX6IAWwF-HcaAIAQO5-KW+1Pw49H4a4MavqBrmkYqTbcHoBZLzgOIxJR8hp2u5BMpnWzxu+PQAgAN30OAKBbAhWuoAnnuAO4pqp4AaYW164nEbsJv8wGOb8johYEEXXPoQyAEJYbW+HEd3AZzoDgz5aQW7jGYCBgEkZh-HoVXoCgggIYgKGYenKLdw8sUfGs4QoLF6gJaln3JIxsg5dMviwGV+PxDVtRNe13W7oNx7CZek3vt3C2dat6gbc++32bYzm2lWsuebdnsPe9g7fbKmXqrhgYseQcOoEj6PY5V+vE6E5Ptt26HQ8z7zYsubZbmmPPcBCIA