جارٍ التحميل...
جارٍ التحميل...
A handful of TypeScript 5.x features changed how I write code day-to-day on the Templately admin and sapan.dev. Notes on the ones I reach for constantly — `satisfies`, `const` type parameters, `using` — and the ones I have not yet found a real use for.
On the Templately admin, the cleanup pass after upgrading to TypeScript 5 was a study in how much friction a few new features can remove. The `satisfies` operator alone replaced a dozen awkward `as const` assertions in our config objects. The new `const` type parameters fixed a handful of generic helpers that had been quietly widening literal types for years. Below are the TS 5 features I now reach for constantly, the ones I rarely use, and the changes the upgrade actually made to working code.
TypeScript has been on a remarkable trajectory. Each release brings features that feel like they should have existed from the start. TypeScript 5.x in particular delivered several quality-of-life improvements that I now consider essential in every project.
Before const type parameters, getting TypeScript to infer literal types from generic functions required awkward workarounds. Now you can annotate a type parameter with const and TypeScript infers the narrowest possible type.
// Before: TypeScript infers string[]
function makeArray<T>(items: T[]): T[] {
return items;
}
const arr = makeArray(['a', 'b']); // string[]
// After: TypeScript infers ["a", "b"]
function makeArray<const T extends readonly unknown[]>(items: T): T {
return items;
}
const arr = makeArray(['a', 'b'] as const); // readonly ["a", "b"]TypeScript 5.0 finally shipped the TC39 Stage 3 decorators spec, replacing the experimental decorators that required a compiler flag. This means your decorators are now standards-compliant and future-proof.
function log(target: any, context: ClassMethodDecoratorContext) {
return function (this: any, ...args: any[]) {
console.log(`Calling ${String(context.name)}`);
return target.call(this, ...args);
};
}
class UserService {
@log
getUser(id: string) {
return fetch(`/api/users/${id}`);
}
}The satisfies operator validates that a value conforms to a type without widening it. This is incredibly useful for configuration objects where you want both type safety and inference of literal types.
type Colors = 'red' | 'green' | 'blue';
type ColorConfig = { [K in Colors]?: string };
// Without satisfies: palette.red is string | undefined
const palette: ColorConfig = { red: '#ff0000', green: '#00ff00' };
// With satisfies: palette.red is "#ff0000" (literal type)
const palette = {
red: '#ff0000',
green: '#00ff00',
} satisfies ColorConfig;TypeScript 5.2 added the using keyword, implementing the TC39 Explicit Resource Management proposal. Resources with a [Symbol.dispose]() method are automatically cleaned up when they leave scope.
function getConnection() {
const conn = openDBConnection();
return {
query: conn.query.bind(conn),
[Symbol.dispose]() {
conn.close();
},
};
}
function processData() {
using conn = getConnection(); // auto-closes on scope exit
return conn.query('SELECT * FROM users');
}نصيحة
Enable useDefineForClassFields and the new decorator support in your tsconfig. Set target to ES2022 or later for the best compatibility with modern decorators.
Beyond language features, TypeScript 5.x brought significant build performance improvements. The new module resolution modes (bundler, node16, nodenext) more accurately reflect how modern bundlers resolve modules, reducing false type errors.
Across the Templately admin, sapan.dev, and the smaller side projects I have rewritten in the past year, three TS 5 features come up constantly: `satisfies` (every config object), `const` type parameters (any helper that takes a tuple of options), and the new module resolution modes (which finally got Vite-resolved imports working without phantom red squiggles). Decorators I have not used yet — most of my code is functional and the use cases haven't shown up. `using` declarations are useful but niche; I have used them exactly once, for a Firebase admin connection in a test setup. Worth knowing the whole feature set, but it is OK if you only use the three above.
المزيد في TypeScript
On the Templately admin we had four different ID types passed around as strings — TemplateId, CategoryId, UserId, OrganizationId — and the bugs that came from mixing them were hard to spot in code review. Branded types fixed that. Notes on the pattern and when it actually pays off.
On TubeOnAI we wired Zod into every API boundary, every form, and every Firebase response — and the next month our error tracker stopped recording shape-mismatch bugs entirely. Notes on the Zod patterns I now reach for by default.
On TubeOnAI, the original load/error/data form state was three independent booleans — and we kept hitting bugs where data was set AND loading was true. Switched to a single discriminated union and the entire class of bugs went away. Notes on the pattern that changed how I model state.