Created
January 8, 2023 18:27
-
-
Save gvergnaud/d79c00b61e383bd5e7e7ced2ff59d295 to your computer and use it in GitHub Desktop.
Can you express any mapped types in terms of recursive + distributive union type?
This file contains 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
// mapped type version | |
type Fn<T> = { | |
[K in keyof T]: [K, T[K]] /* arbitrary fn using K and T[k] */; | |
}; | |
// distributive union version | |
type Fn2<T> = FromEntries< | |
keyof T extends infer K | |
? K extends keyof T | |
? [K, [K, T[K]] /* arbitrary fn using K and T[k] */] | |
: never | |
: never | |
>; | |
type UnionToIntersection<T> = (T extends any ? (p: T) => void : never) extends ( | |
p: infer I | |
) => void | |
? I | |
: never; | |
type Compute<T> = { [K in keyof T]: T[K] } & unknown; | |
type FromEntries<Entry extends [PropertyKey, unknown]> = Compute< | |
UnionToIntersection<Entry extends any ? Record<Entry[0], Entry[1]> : never> | |
// ^ | |
// This is cheating a bit because Record is defined as a simple map type. | |
>; | |
type res1 = Fn<{ age: number; name: string }>; | |
type test1 = Expect< | |
Equal<res1, { age: ["age", number]; name: ["name", string] }> | |
>; | |
type res2 = Fn2<{ age: number; name: string }>; | |
type test2 = Expect< | |
Equal<res2, { age: ["age", number]; name: ["name", string] }> | |
>; | |
/** | |
* Secret Helpers! 🤫 | |
*/ | |
/** | |
* `Equal` takes 2 types and returns `true` if they are the same. | |
*/ | |
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends < | |
T | |
>() => T extends Y ? 1 : 2 | |
? true | |
: false; | |
/** | |
* `Expect` takes one type parameter and only typechecks if it is true. | |
*/ | |
type Expect<T extends true> = T; | |
// Playground: https://www.typescriptlang.org/play?#code/C4TwDgpgBAYgdgHgCoD4oF4oG8BQUoDaA0lAJZxQDWEIA9gGZRIC6AXIUQDRPHPNQB6AFRQAhgCcARqWDiJIKPQoBXAM7kA5lBKi4AEx6V+UIQIDcOAL4WcAgVACaEVd0nLgZYAHJVYqAAtRVVUAGwhWHFBIWDgAJmQ0TBhxWgBbAFE4WVJnBDwqGgYmKAgAD2AIfV9yeghxbXz8AH5tEvLKvV9qOkYkRvwoFuJuYZ4iPkERCWlZeUUVdTgtHX1DY1Nmfvx2OAgANzr+nf3DlBso6ABVOFJaOCRaAEksutUIAGNgW8RUDCgACiQbQqVTEcAULX+YHYSAAlBg0HtaKQDMcDuJ4WUQZ0AfloWQ4LV6o8cPD0IjkXp8i0SdsoLt0edwNAAMJpMDuCAJP5YDgEgo9JhsMb8SxQABkUGUcEocFoAHc4Ezosk0plsrl1eIFFiOr4CAAFFKQcSgIg0bjS2UKuDMRJQNmpDkVPL4a7fB7PCriN6fb4ILU69qg3QQqAAJQ+tHEegDWW1BAADMxuIGCABGO1QNF1FD5OwDQtF4sl0tFgB6+fsRaQ-lI1V8738EFEXyWfhmUEkH1Eamgkfe0YM9agegg9HIEAMQT86idYSgqVEYCgFwAdDgzjhIsyoOJnOm-vAELzRBpwvTlKlu+IzPTRKkL6psu3LFuLqvnMBD5h0qVIJ8rpQOkACOyiiCECD7qo6bcKe57sAQABEZ4QEh3BwFeN7MHecAPheyF4Y+6FQM+4iaKKeZbju0TQbER5xCeYgIZe151Lh+HsGRmhQG+FgfhUz70b+-4fMAQGgeBkF0XBzEESh54kZhbHiDh96PohSFEWh3DcUslGbjYthCEIeAiAAyh8+4eAAEhAIQmqoACEUCAHwbgDUu2ZAjbsIpkmFAAAGkkQQFq6iNQvj0Rcvi6AY1nKOIcC+AFsjKBAoWkIwwDNgoEjQNl0CqPhG4mN5H7BZBAAa3AOPa-wJP8ZJoECuqgpVgxQIe7CxJiwY4kBfQoI1CLFK1OIOB1XVQLE1KruIaX5Ow9AQW8Ni+WZgV-gBwChcA4XOFAdz5buYASPh3pggYdwhAoFxNh8lDVIwMhkL4qUQCVpg0dAW1icgwJ6nNaX2kgFhAA |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment