Last active
August 12, 2025 17:37
-
-
Save SirSerje/2479880e641aaa5a17309524cf6fc4e4 to your computer and use it in GitHub Desktop.
Typescript Snippets By SirSerje
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
| // Part 1 — Senior Dev Gatekeeper | |
| // 1) `satisfies` (TS 4.9) | |
| // Without | |
| type User = { id: number; role: 'admin' | 'user' }; | |
| const u1: User = { id: 1, role: 'admin', extra: true as any }; // error | |
| // With | |
| const u2 = { id: 1, role: 'admin' } satisfies User; | |
| --- | |
| window.customData = { theme: 'dark' }; // TS2339 | |
| console.log(window.customData?.theme); // TS2339 | |
| // ❌ BEFORE — No augmentation, causes TS2339 | |
| window.customData = { theme: 'dark' }; | |
| console.log(window.customData?.theme); | |
| // ✅ AFTER — In a .d.ts file (e.g., global.d.ts) | |
| export {}; // ensures this is treated as a module | |
| declare global { | |
| interface Window { | |
| customData?: { theme: string }; | |
| } | |
| } | |
| // main.ts | |
| window.customData = { theme: 'dark' }; | |
| console.log(window.customData?.theme); // works | |
| --- | |
| // 3) `Record` coverage with `satisfies` | |
| // Without | |
| type Route = 'home' | 'profile' | 'settings'; | |
| const paths1: { [k: string]: string } = { home: '/', profile: '/p' }; // nah | |
| // With | |
| const paths2 = { | |
| home: '/', | |
| profile: '/p', | |
| settings: '/s' | |
| } satisfies Record<Route, string>; // nice |
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
| // Part 2 — Code Cleaner | |
| // 1) Generics | |
| // ❌ no generics | |
| function wrapInArray1(value: number): number[] { | |
| return [value]; | |
| } | |
| const a1 = wrapInArray1(5); // ok | |
| // const b1 = wrapInArray1("hi"); // ❌ error | |
| // ✅ with <T> - flexible | |
| function wrapInArray2<T>(value: T): T[] { | |
| return [value]; | |
| } | |
| const a2 = wrapInArray2(5); // number[] | |
| const b2 = wrapInArray2("hi"); // string[] | |
| const c2 = wrapInArray2({ id: 1 }); // { id: number }[] | |
| // 2) `keyof typeof` | |
| // ❌ no checks for keys | |
| type StatusKey = string; | |
| const statuses: Record<StatusKey, number> = { | |
| open: 1, | |
| closed: 2, | |
| pending: 3, | |
| archive: 4, // ← throws error as expected | |
| }; | |
| // With ✅ | |
| const allowedStatuses = { open: 1, closed: 2, pending: 3 } as const; | |
| type StatusKey = keyof typeof allowedStatuses; | |
| // 'open' | 'closed' | 'pending' | |
| const statuses: Record<StatusKey, number> = { | |
| open: 10, | |
| closed: 20, | |
| pending: 30, | |
| // archive: 40, // ❌ TS error — no key | |
| }; | |
| // 3) User-defined type guards (`is`) | |
| // Without | |
| function getId1(x: unknown) { return (x as any)?.id ?? null; } | |
| // With | |
| type WithId = { id: string | number }; | |
| function hasId(x: unknown): x is WithId { | |
| return typeof x === 'object' && x !== null && 'id' in x; | |
| } | |
| function getId2(x: unknown) { return hasId(x) ? x.id : null; } |
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
| // Part 3 — Absolutely Nuts | |
| // 1) Template literal types | |
| // Without | |
| type EventName1 = 'user_created' | 'user_deleted' | 'order_created' | 'order_deleted'; | |
| // With | |
| type Entity = 'user' | 'order'; | |
| type Action = 'created' | 'deleted'; | |
| type EventName2 = `${Entity}_${Action}`; | |
| // 2) `as const` literal inference | |
| // ❌ Without | |
| const roles1 = ['admin', 'user', 'guest']; | |
| // roles1: string[] | |
| type Role1 = typeof roles1[number]; | |
| // Role1 = string ← losing specifics | |
| // ✅ With | |
| const roles2 = ['admin', 'user', 'guest'] as const; | |
| // roles2: readonly ["admin", "user", "guest"] | |
| type Role2 = typeof roles2[number]; | |
| // Role2 = "admin" | "user" | "guest" ← exact values | |
| // 3) Decorators (TS experimental) | |
| // Without | |
| class Repo1 { | |
| getById(id: string) { return { id }; } | |
| } | |
| // With | |
| function Log(_t: any, k: string, d: PropertyDescriptor) { | |
| const orig = d.value; | |
| d.value = function (...args: any[]) { | |
| console.time(k); | |
| const r = orig.apply(this, args); | |
| console.timeEnd(k); | |
| return r; | |
| }; | |
| } | |
| class Repo2 { | |
| @Log | |
| getById(id: string) { return { id }; } | |
| } |
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
| // Part 4 — Beyond AI | |
| // 1) Simple `infer` | |
| // Without | |
| type Elem1<T> = T; // no flex(ibility) | |
| // With | |
| type ElementType<T> = T extends (infer U)[] ? U : T; | |
| type A = ElementType<string[]>; // string | |
| type B = ElementType<number>; // number | |
| // 2) Type guard (`is`) | |
| type Fish = { swim: () => void }; | |
| type Bird = { fly: () => void }; | |
| function getSmallPet(): Fish | Bird { | |
| return Math.random() > 0.5 | |
| ? { swim: () => console.log('Swimming...') } | |
| : { fly: () => console.log('Flying...') }; | |
| } | |
| // 😪 clumsy | |
| let pet = getSmallPet(); | |
| if ((pet as Fish)?.swim) { | |
| (pet as Fish).swim(); | |
| } else { | |
| (pet as Bird).fly(); | |
| } | |
| // 😏 better way | |
| function isFish( | |
| pet: Fish | Bird | |
| ): pet is Fish { | |
| return (pet as Fish).swim !== undefined; | |
| } | |
| if(isFish(pet)) { | |
| pet.swim() | |
| } else { | |
| pet.fly() | |
| } | |
| //😃 | |
| type User2 = { name: string }; | |
| // ❌ | |
| function ensureUser1(x: any) { | |
| if (!x?.name) throw new Error('bad'); | |
| } | |
| function greetBad(u: unknown) { | |
| ensureUser1(u); | |
| // ❌ TS: 'u' is unknown | |
| u.name.toUpperCase(); | |
| } | |
| // ✅ using assertion: | |
| function assertUser(x: any): asserts x is User2 { | |
| if (typeof x?.name !== 'string') throw new Error('bad'); | |
| } | |
| function greetGood(u: unknown) { | |
| assertUser(u); // TS knows its User2 | |
| u.name.toUpperCase(); // ✅ OK | |
| } |
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
| // Part 5 — Squeaky Clean Finale | |
| // 1) `readonly` arrays/tuples | |
| // Without | |
| function useA1(nums: number[]) { nums.push(99); } | |
| // With | |
| function useA2(nums: readonly number[]) { /* no mutation allowed */ } | |
| // 2) Utility types `Pick` / `Omit` | |
| // Without | |
| type UserFull = { id: string; name: string; email: string; age: number }; | |
| type UserPublic1 = { id: string; name: string }; | |
| // With | |
| type UserPublic2 = Pick<UserFull, 'id' | 'name'>; | |
| type UserPrivate2 = Omit<UserFull, 'email'>; | |
| // 3) Namespaces + untyped 3rd-party lib wrapper | |
| declare const ThirdPartyAPI: any; | |
| // Without | |
| const raw = ThirdPartyAPI.send({ sz: 12, tp: ['x'] }); | |
| // With | |
| namespace Vendor { | |
| export namespace Orders { | |
| export type CreateInput = { size: number; tags: string[] }; | |
| export type CreateResult = { id: string; eta: number }; | |
| export function create(input: CreateInput): CreateResult { | |
| return ThirdPartyAPI.send({ sz: input.size, tp: input.tags }); | |
| } | |
| } | |
| } | |
| const order = Vendor.Orders.create({ size: 12, tags: ['x'] }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment