Skip to content

Instantly share code, notes, and snippets.

@yue4u
Last active June 12, 2022 18:07
Show Gist options
  • Save yue4u/92b96297c429259b74355c4ac0a83d3c to your computer and use it in GitHub Desktop.
Save yue4u/92b96297c429259b74355c4ac0a83d3c to your computer and use it in GitHub Desktop.
Typed page state
// @see https://www.typescriptlang.org/play?ssl=40&ssc=2&pln=1&pc=1#code/C4TwDgpgBACghgc2gXigcjmqAfdAjLXNAYzQChRIoBhAVwCd6IA7YeJAHhgAkA+KVDygQAHsBYATAM6xEEbgEspwAPb0QHANoA6XXGYgANFAXMAZhHqwAuvwD8sYWMkzl9UwigOYUAFzoIAFswUCx-ZggAN0sKcGgAOThIgFFGNS4ncWZpKDcPY2pMl1zgd2YEflQAA1FIYmAoYgYmVigwOShVKDxoAB0qgBIAbxgAX37u2gazFVpsqH7h6nGqqtiqAEFIuAAbBTg8HYgubiLsmXZ5JVV1Y2SROrYO0Sycy+MAMWZKmmaWJ84PH4L2K90ely8UC+figiRSaXoHDBEHq71+jH+lxOvF4ZDIpnE9DMcGI0EuimUag0FJuIDObzkmmsAigTP4QzIUC5nRUGRB51kSF4AAp2kh-DAAJT+OBSKSWYAyYAACyUJguchpVK0um0WtuNlx3KgcDAYCO-i2u32h2OKqUxgwaGMwslAn4MHoKkCSmOGDNRzQOM53Lw+nDlu2ewORw49qkjoILrdyA9Xp98o4aDDzHDQaN3OIyss6kj1pjdtVCfQpGT7tg6d9WaLJZA+bIozxZjm9QUKmYnQgyldUA5xuI-eUbQlmuuVJZQ1GJpk+hAZAA9OvjcaAHp2ENcsDaU3miCujdb7l7g9tbSqYVOyUX3f741Hk9Hc+bl83o858NfpeXLXm+2gtowICAT+oH3iQaBPt+V6vtyR7geoUFIb+d4qA+BAIUBUAgShx4Bme+HQcR-65hhwHIYe2EPpg5GEXRt4fmRz6YaMQA
type Page = 'a' | 'b' | 'c'
type CurrentPage<PH> = PH extends PageHistory<[...any, infer P]> ? P extends string ? P : 'empty' : never
type NavError<P extends string, C extends string> = `expect current page to be \`${P}\` but found \`${C}\``
type Avaliable<PH extends PageHistory, ExpectPage extends Page, Fn> = CurrentPage<PH> extends ExpectPage ? Fn : NavError<ExpectPage, CurrentPage<PH>>
interface PageHistory<History extends Page[] = []> {
to<P extends Page>(page: P): asserts this is PageHistory<[...History, P]>
apple: Avaliable<this, 'a', () => Promise<'apple'>>
banana: Avaliable<this, 'b', () => Promise<'banana'>>
cherry: Avaliable<this, 'c', () => Promise<'cherry'>>
}
function test() {
const p: PageHistory = {} as any
// ^?
p.apple()
// ^?
p.to('a')
// ^?
p.apple()
// ^?
p.banana()
// ^?
p.cherry()
// ^?
p.to('c')
// ^?
p.cherry()
// ^?
p.to('b')
// ^?
p.apple()
// ^?
p.banana()
// ^?
p.to('a')
// ^?
p.apple()
// ^?
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment