Last active
October 17, 2023 10:01
-
-
Save AriPerkkio/8b64d61be614177ae9d04d8f79419a97 to your computer and use it in GitHub Desktop.
Type definition utils I keep forgetting
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
// https://www.typescriptlang.org/play?#code/C4TwDgpgBAggNnA0hEBnA8mYBLA9gOwEM4AeAFSggA9gJ8ATVKAbygG1EAuKVYAJ2z4A5gF1uhfCCgBfAHxQAvCwBQUNe0RRBUANYpcAMyhkRAfm5kOIgNzLpt5aEhQAqvjz4yuGHz6EQJKrqbh5k4NDUtAxMvALCADRBaj5+IGHOkXSMPPyCQmwiiuwiyvJKzEnsAMq5wgAy2LR+cFr4ru4E6RBiUACiVADGcACu9BAkIZ3h8VA1cUINTcTymdFQ+BAAbhB8lepQpuwAdCcp-l0zc3mLO8Ql+-vck57evv4k-UOj488Xs7ULRq3OCyGZsE5HM5pab-eY3ZoiWS2aRsX7hQoAMhy8wKDmUAHp8cYILxUI5wrNcABbCBdIoAcnQADlevSoAAfKD0sgAdXQbM53IAEgAlXqshyCJoGQgDaAAWRAAEl8NLZdAKmonBBuFVqbTwrY1EQadxYnkjVp6GaAZa4NheDacTY7MplAMCLxYNxFSq1XKiqxtdxGSz6TMTTquTBw1aQzAAIyx+2O9j0pMzekAJnpIns7s9wCgACFuPAkCgMFgPMQSL7VTsZXKyix1oRTdG2fmC-gvQ1eOgDHqaV0MHwxnwINb2qFXqkSMODZAW2xQ6zM7z+RvReLc7YPb2i-3gIPF6O3Lhxzsnh0XlCF-quivhWL11zN7G13u3YSoAABYBUAAWmoSABmAEDfEvHs+wdE8h0fcJUHlB1UDyG9Z3vM9wmfD9M2ZVkXQJIkAOA0CIHAyC+Ggg9YIHBCRyQtwdHwXAAHd8AANWIYYo1+Od3mw5cilXAjPzwrkADF0BcEVv2I-9AJAqgwIgnZqN2Wijzg09EMgVBmNYjjuJGCAswwzoBICISIGfMSNz5cSdzfelpNk+Tf1I5TVKomjCygY9dMY-S6joIRgAACyZXBgHlQhgAGCL0JnSysL02yRK-Byt3fZynNfeSgA | |
type AllKeysOptional<T extends { [K: string]: any }> = { | |
[K in keyof T]?: T[K]; | |
}; | |
type UnionToArray< | |
UnionType extends string, | |
ArrayType extends string[] = [] | |
> = { | |
[StringLiteral in UnionType]: Exclude<UnionType, StringLiteral> extends never | |
? [...ArrayType, StringLiteral] | |
: UnionToArray<Exclude<UnionType, StringLiteral>, [...ArrayType, StringLiteral]>; | |
}[UnionType] & string[]; | |
// Tests | |
type SomeType = 'ONE' | 'TWO' | 'THREE'; | |
interface MyInterface { | |
type: SomeType; | |
name: string; | |
id: string; | |
list: string[]; | |
} | |
const A: MyInterface = { type: 'ONE', name: 'A', id: 'A1', list: ['1', '2']}; | |
const B: AllKeysOptional<MyInterface> = { name: 'A' }; | |
const ListOfSomeTypesOrdered: UnionToArray<SomeType> = ['ONE', 'TWO', 'THREE']; | |
const ListOfSomeTypesUnorder: UnionToArray<SomeType> = ['THREE', 'TWO', 'ONE']; | |
// @ts-expect-error | |
const ListOfSomeTypesMissing: UnionToArray<SomeType> = ['TWO', 'ONE']; | |
// @ts-expect-error | |
const ListOfSomeTypesUnknownValue: UnionToArray<SomeType> = ['ONE', 'TWO', 'FOUR']; | |
// @ts-expect-error | |
const ListOfSomeTypesUnknownValue2: UnionToArray<SomeType> = ['ONE', 'TWO', 'THREE', 'FOUR']; | |
// @ts-expect-error | |
const ListOfSomeTypesLengthNotMatching: UnionToArray<SomeType> = ['ONE', 'TWO', 'THREE', 'THREE']; | |
/* | |
* Nominal types, a.k.a. opaque types, branded types, tagged types | |
*/ | |
// This is set in module scope and not exported | |
// so that developers cannot access user.id[UserID] | |
declare const UserID: unique symbol; | |
interface User { | |
name: string; | |
id: string & { readonly [UserID]: never }; | |
someOtherId: string; | |
} | |
function getUsers(): User[] { | |
return []; | |
} | |
function getUserDetails(id: User['id']) { | |
return fetch(`/users/${id}`); | |
} | |
const users = getUsers(); | |
// OK | |
users.forEach(user => getUserDetails(user.id)); | |
// @ts-expect-error | |
users.forEach(user => getUserDetails(user.someOtherId)); | |
// This works here in demo but won't work outside module scope | |
users[0].id[UserID]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment