80 phút
Advanced TypeScript Patterns và Performance
Decorators và Metadata
Class Decorators
function LogClass(target: Function) {
console.log(`Class ${target.name} was defined`);
}
function Entity(tableName: string) {
return function<T extends { new(...args: any[]): {} }>(constructor: T) {
return class extends constructor {
public readonly tableName = tableName;
};
};
}
@LogClass
@Entity('users')
class User {
constructor(public name: string, public email: string) {}
}
const user = new User('John', 'john@example.com');
console.log((user as any).tableName); // 'users'
Method Decorators
function LogMethod(
target: any,
propertyName: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyName} with args:`, args);
const result = originalMethod.apply(this, args);
console.log(`${propertyName} returned:`, result);
return result;
};
return descriptor;
}
class Calculator {
@LogMethod
add(a: number, b: number): number {
return a + b;
}
}
Property Decorators
function MinLength(length: number) {
return function(target: any, propertyName: string) {
let value: string;
const getter = () => value;
const setter = (newValue: string) => {
if (newValue.length < length) {
throw new Error(
`${propertyName} must be at least ${length} characters long`
);
}
value = newValue;
};
Object.defineProperty(target, propertyName, {
get: getter,
set: setter
});
};
}
class User {
@MinLength(3)
username: string;
constructor(username: string) {
this.username = username;
}
}
Mixins
Mixin Pattern
type Constructor<T = {}> = new (...args: any[]) => T;
function Timestamped<TBase extends Constructor>(Base: TBase) {
return class extends Base {
timestamp = new Date();
};
}
function Activatable<TBase extends Constructor>(Base: TBase) {
return class extends Base {
isActive = false;
activate() {
this.isActive = true;
}
deactivate() {
this.isActive = false;
}
};
}
class User {
constructor(public name: string) {}
}
const TimestampedActivatableUser = Timestamped(Activatable(User));
const user = new TimestampedActivatableUser('John');
user.activate();
console.log(user.timestamp, user.isActive);
Performance Optimization
const assertions
// Thay vì
const colors = ['red', 'green', 'blue']; // string[]
// Sử dụng const assertions
const colors = ['red', 'green', 'blue'] as const; // readonly ["red", "green", "blue"]
// Objects với const assertions
const user = {
name: 'John',
age: 30,
permissions: ['read', 'write']
} as const;
// user.name = 'Jane'; // Error!
Satisfies Operator
interface Config {
color: 'red' | 'green' | 'blue';
size: 'small' | 'medium' | 'large';
}
const config = {
color: 'red',
size: 'medium'
} satisfies Config;
// TypeScript biết config.color là 'red' | 'green' | 'blue'
// nhưng vẫn giữ literal type 'red'
Template Literal Types Performance
// Có thể gây performance issues với types phức tạp
type Color = 'red' | 'green' | 'blue';
type Size = 'small' | 'medium' | 'large';
// Tốt
type ButtonVariant = `${Color}-${Size}`;
// Có thể gây issues
// type AllCombinations = `${Color}-${Size}-${Variant}...`;
Advanced Conditional Types
Recursive Types
type JsonValue =
| string
| number
| boolean
| null
| JsonValue[]
| { [key: string]: JsonValue };
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? DeepReadonly<T[P]>
: T[P];
};
type DeepRequired<T> = {
[P in keyof T]-?: T[P] extends object
? DeepRequired<T[P]>
: T[P];
};
Template Literal Types Manipulation
type EventName = 'click' | 'scroll' | 'keypress';
type HandlerName<T extends string> = `on${Capitalize<T>}`;
type EventHandlers = {
[K in EventName as HandlerName<K>]: (event: Event) => void;
};
// {
// onClick: (event: Event) => void;
// onScroll: (event: Event) => void;
// onKeypress: (event: Event) => void;
// }
// Advanced manipulation
type GetterName<T extends string> = `get${Capitalize<T>}`;
type SetterName<T extends string> = `set${Capitalize<T>}`;
type Accessors<T extends string> =
| GetterName<T>
| SetterName<T>;
Type-Level Programming
Type-Level Arithmetic
type Length<T extends any[]> = T['length'];
type BuildArray<
N extends number,
T extends any[] = []
> = T['length'] extends N
? T
: BuildArray<N, [...T, any]>;
type Add<A extends number, B extends number> =
Length<[...BuildArray<A>, ...BuildArray<B>]>;
type Subtract<A extends number, B extends number> =
BuildArray<A> extends [...BuildArray<B>, ...infer R]
? Length<R>
: never;
type Result1 = Add<5, 3>; // 8
type Result2 = Subtract<8, 3>; // 5
String Manipulation ở Type Level
type Split<
S extends string,
D extends string
> = S extends `${infer T}${D}${infer U}`
? [T, ...Split<U, D>]
: [S];
type Join<
T extends string[],
D extends string
> = T extends [infer F, ...infer R]
? R extends string[]
? F extends string
? `${F}${D}${Join<R, D>}`
: never
: F
: '';
type Path = 'users/123/profile';
type Parts = Split<Path, '/'>; // ['users', '123', 'profile']
type Reconstructed = Join<Parts, '-'>; // 'users-123-profile'
Compiler Performance
Project References
// tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true
},
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" }
]
}
Incremental Builds
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./.tsbuildinfo"
}
}
Skip Lib Check khi có thể
{
"compilerOptions": {
"skipLibCheck": true
}
}