Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Miscellaneous cases and concepts for TypeScript/Node.js refactoring, supplementing the core refactoring guide. Covers additional patterns, edge cases, and specialized refactoring techniques that don't fit into the core refactoring principles. Suitable for: (1) Handling complex refactoring scenarios, (2) Solving code smells not covered by standard guides, (3) Advanced TypeScript patterns, (4) Node.js specific considerations, (5) React/JSX/HTML/DOM specific considerations, and (6) Cross-domain con
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 346% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 289% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 562% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 290% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 413% | 0% |
You are an expert in handling complex and specialized refactoring scenarios that go beyond standard patterns. This guide supplements the core refactoring principles, providing additional cases, edge conditions, and advanced techniques.
> Purpose of this guide: > - Handle edge cases: Covers refactoring scenarios not addressed by standard patterns > - Advanced patterns: Specialized techniques for complex TypeScript/Node.js situations > - Cross-domain concerns: Refactoring considerations that span multiple domains > - Practical supplements: Real-world complex situations and their solutions
code-refactoring-expert-typescript - Core refactoring principles
Problem: Unnecessary sequential execution of independent asynchronous operations.
typescriptasync function processUserData(userId: string) { const user = await fetchUser(userId); // Wait for completion const profile = await fetchProfile(userId); // Wait for completion const settings = await fetchSettings(userId); // Wait for completion return { user, profile, settings }; }
typescriptasync function processUserData(userId: string) { const [user, profile, settings] = await Promise.all([ fetchUser(userId), fetchProfile(userId), fetchSettings(userId) ]); return { user, profile, settings }; }
typescriptasync function processUserDataSafe(userId: string) { const results = await Promise.allSettled([ fetchUser(userId), fetchProfile(userId), fetchSettings(userId) ]); return { user: results[0].status === 'fulfilled' ? results[0].value : null, profile: results[1].status === 'fulfilled' ? results[1].value : null, settings: results[2].status === 'fulfilled' ? results[2].value : null, errors: results.filter(r => r.status === 'rejected').map(r => r.reason) }; }
Problem: Loading all data into memory when processing large datasets.
typescriptasync function processAllRecords() { const allRecords = await fetchAllRecords(); // Could be millions of records! for (const record of allRecords) { await processRecord(record); } }
typescriptasync function* processRecordsGenerator(): AsyncGenerator<Record> { let cursor = null; do { const { records, nextCursor } = await fetchRecordsBatch(cursor); for (const record of records) { yield record; } cursor = nextCursor; } while (cursor); } async function processAllRecords() { for await (const record of processRecordsGenerator()) { await processRecord(record); } }
Problem: Creating types from string patterns.
typescriptenum EnumHttpMethod { GET = 'GET', POST = 'POST', PUT = 'PUT', DELETE = 'DELETE' } type IEndpoint = `/api/${EnumHttpMethod}/${string}`; function handleRequest(endpoint: IEndpoint) { /* ... */ } handleRequest('/api/GET/users'); // Valid handleRequest('/api/PATCH/users'); // Invalid
Wrap loosely-typed external APIs (like VS Code Memento, localStorage, etc.) into strictly-typed internal interfaces, achieving compile-time type safety and runtime data consistency.
External APIs typically use string keys + any values for maximum flexibility:
typescript// External API type definitions are too loose interface Memento { get<T>(key: string): T | undefined; // key is any string update(key: string, value: any): void; // value is any } // Problems from direct usage context.globalState.get('serchHistory'); // Typo! Compiler won't complain context.globalState.update('selectedIDEs', 'x'); // Type error! Should be number[]
typescriptexport const enum EnumGlobalStateName { searchHistory = 'searchHistory', selectedIDEs = 'selectedIDEs', } // Define value type for each key export interface IGlobalStateSearchHistory { key: EnumGlobalStateName.searchHistory; value: string[]; } export interface IGlobalStateSelectedIDEs { key: EnumGlobalStateName.selectedIDEs; value: number[]; } export type IGlobalStateAll = IGlobalStateSearchHistory | IGlobalStateSelectedIDEs;
typescriptexport class VscodeExtensionContextGlobalState { constructor(protected globalState: Memento) {} /** * Use generic conditional types to implement key-to-value type mapping * K extends EnumGlobalStateName: Restricts key to enum values * Extract<IGlobalStateAll, { key: K }>: Extracts matching interface from union type * T["value"]: Gets the value type of that interface */ get<K extends EnumGlobalStateName, T extends Extract<IGlobalStateAll, { key: K }>>( key: K, defaultValue?: T["value"] ): T["value"] | undefined { return this.globalState.get(key, defaultValue); } update<K extends EnumGlobalStateName, T extends Extract<IGlobalStateAll, { key: K }>>( key: K, value: T["value"] ): Thenable<void> { return this.globalState.update(key, value); } }
typescriptconst state = new VscodeExtensionContextGlobalState(context.globalState); // Key names have IntelliSense and compile-time checks const history = state.get(EnumGlobalStateName.searchHistory); // ^? Type inferred as string[] | undefined // Key name errors are caught immediately state.get('serchHistory'); // Error: Type mismatch // Value types have compile-time checks state.update(EnumGlobalStateName.selectedIDEs, [1, 2, 3]); // number[] state.update(EnumGlobalStateName.selectedIDEs, 'invalid'); // Type error!
| Benefit | Description | |---------|-------------| | Compile-time type safety | Key name typos, value type errors caught at compile time | | IntelliSense | IDE provides key name autocomplete and value type hints | | Refactorability | Renaming enum values can be done via IDE global refactoring | | Backward compatibility | When underlying external API changes, only modify the wrapper layer |
globalState / workspaceStatelocalStorage / sessionStoragestring key + any value external APIIn large projects, integrate GlobalState wrapper into an abstract base class to simplify state management across multiple classes:
typescript/** * Auto-initialize GlobalState from ExtensionContext * Implement lazy-loading via getter */ export abstract class AbstractClassWithContextGlobalState { protected context!: ExtensionContext; #globalState!: VscodeExtensionContextGlobalState; protected get globalState(): VscodeExtensionContextGlobalState { if (!this.#globalState) { this.#globalState = new VscodeExtensionContextGlobalState(this.context.globalState); } return this.#globalState; } } // Usage export class MyController extends AbstractClassWithContextGlobalState { async saveData(data: string[]): Promise<void> { await this.globalState.update(EnumGlobalStateName.searchHistory, data); } }
typescriptexport function newVscodeExtensionContextGlobalState(globalState: ExtensionContext["globalState"]) { return new VscodeExtensionContextGlobalState(globalState); } // Usage const state = newVscodeExtensionContextGlobalState(context.globalState);
Full case reference: External API Type-Safe Wrapper Pattern
Refactor scattered and fragile hardcoded DOM element IDs and CSS class selectors in frontend applications into a unified Enum management system, establishing a Single Source of Truth.
Using hardcoded strings to reference UI elements carries the following risks:
id and className in HTML and JSX templates are also risk sources. And compared to JS code, HTML/JSX maintenance is harder to spot issues (lack of type checking, opaque cross-file references), making them easier to miss during refactoringtypescript// Hardcoded IDs - difficult to maintain, error-prone const element = document.getElementById('searchResults'); const input = document.getElementById('searchInput') as HTMLInputElement; // Hardcoded CSS class selectors const radio = document.querySelector<HTMLInputElement>('.ide-source-radio:checked');
EnumWebviewElemId and EnumCssClassSelector - Define unified identifiers for DOM element IDs and CSS classes, serving as string bridges connecting code and HTML.
typescript/** * DOM element ID enum (Single Source of Truth) */ export const enum EnumWebviewElemId { /** Search results container */ searchResults = 'searchResults', /** Search input field */ searchInput = 'searchInput', /** Message display container */ message = 'message', } /** * CSS class selector enum (Single Source of Truth) */ export const enum EnumCssClassSelector { /** Tab navigation container */ tabs = 'tabs', /** IDE checkbox */ ideCheckbox = 'ide-checkbox', /** IDE source radio button */ ideSourceRadio = 'ide-source-radio', }
EnumTabName - Defines semantic identifiers for business states and behaviors (like tab names, operation modes), keeping logic code independent of DOM structure.
typescript/** * Tab name enum - Business semantic identifier */ export const enum EnumTabName { /** Sync settings tab */ sync = 'sync', /** View all settings tab */ values = 'values', /** Selected settings tab */ selected = 'selected', }
typescript/** * Query single element by EnumWebviewElemId */ export function querySelectorById<T extends HTMLElement>(id: EnumWebviewElemId | EnumTabName): T | null { return document.getElementById(id) as T | null; } /** * Query single element by EnumCssClassSelector */ export function querySelectorByClass<T extends HTMLElement>(classSelector: EnumCssClassSelector, suffix?: string): T | null { return document.querySelector<T>(`.${classSelector}${suffix ?? ''}`); } /** * Query all elements by EnumCssClassSelector */ export function querySelectorAllByClass<T extends HTMLElement>(classSelector: EnumCssClassSelector, suffix?: string): NodeListOf<T> { return document.querySelectorAll<T>(`.${classSelector}${suffix ?? ''}`); }
typescript// Using Enum - type safe, maintainable import { EnumWebviewElemId, EnumCssClassSelector, EnumTabName } from './scripts/elem-get'; // Basic element query const searchResults = querySelectorById<HTMLDivElement>(EnumWebviewElemId.searchResults); // With pseudo-class selector const checkedRadio = querySelectorByClass<HTMLInputElement>( EnumCssClassSelector.ideSourceRadio, ':checked' ); // Tab switching logic - using business semantic identifiers ALL_TAB_NAMES.forEach(tabName => { const el = querySelectorById<HTMLDivElement>(tabName); el?.classList.toggle('active', tabName === currentTab); });
| Type | Naming Pattern | Example | Responsibility Level | | :--- | :--- | :--- | :--- | | DOM ID | Enum{Name}ElemId | EnumWebviewElemId | Physical locator (low-level) | | CSS Class | Enum{Name}ClassSelector | EnumCssClassSelector | Physical locator (low-level) | | Tab/State | Enum{Name} (standalone) | EnumTabName | Business semantic identifier (high-level) |
Why this is especially important:
Many developers only focus on refactoring JavaScript logic code, but overlook the hardcoding issues in the HTML/JSX template layer. In fact, HTML/JSX maintenance difficulty is often higher than JS code:
id="sync" in JSX doesn't go through TypeScript compiler checks, typos can only be discovered at runtimejsx// Before - Hardcoded IDs <div id="sync" className="tab-content active"> <div className="section"> <h2>Search & Sync Settings</h2> <div className="search-container"> <input type="text" className="search-input" id="searchInput" /> </div> <div id="searchResults" className="results-container"> {/* Search results */} </div> </div> </div> // After - Using Enums <div id={EnumTabName.sync} className="tab-content active"> <div className="section"> <h2>Search & Sync Settings</h2> <div className="search-container"> <input type="text" className="search-input" id={EnumWebviewElemId.searchInput} /> </div> <div id={EnumWebviewElemId.searchResults} className="results-container"> {/* Search results */} </div> </div> </div>
typescript// Before - Hardcoded tab names export function SettingsNavigation() { return ( <> <button className={`tab${activeTab === 'sync' ? ' active' : ''}`} onClick={() => setActiveTab('sync')}>Sync</button> <button className={`tab${activeTab === 'values' ? ' active' : ''}`} onClick={() => setActiveTab('values')}>Values</button> </> ); } // After - Using EnumTabName export function SettingsNavigation() { return ( <> {ALL_TAB_NAMES.map(tabName => ( <button key={tabName} className={`tab${activeTab.value === tabName ? ' active' : ''}`} onClick={() => { activeTab.value = tabName; }} > {getTabLabel(tabName)} </button> ))} </> ); }
protected Instead of privateUnless there are special requirements or explicit user requests, private is not recommended. It is recommended to default to protected for handling non-public members.
protected allows subclasses to access parent class members, while private completely blocks accessprivate to protected is a breaking changeprivate is only checked at compile time, and can still be accessed at runtime; in comparison, protected provides reasonable encapsulation while retaining extension flexibilitytypescript// Not recommended: Overly restrictive, blocking inheritance possibilities class DataProcessor { private cache = new Map<string, unknown>(); private logger = console; process(data: unknown) { this.logger.log('Processing...'); // Subclass cannot access this.cache and this.logger } } // Recommended: Retain inheritance extension flexibility class DataProcessor { protected cache = new Map<string, unknown>(); protected logger = console; process(data: unknown) { this.logger.log('Processing...'); // Subclass can normally access and override these members } } // Works normally during internal inheritance class ExtendedDataProcessor extends DataProcessor { async processAsync(data: unknown) { // Can access parent's protected members this.logger.log('Async processing...'); const cached = this.cache.get('key'); // ... } }
The following situations may still consider using private:
> Summary: protected is a safer default choice, it strikes a balance between encapsulation and extensibility, avoiding refactoring difficulties due to over-restriction.
This is a guide for choosing between State, RefObject, IRefObjectMaybe<T> (Value/RefObject), and Memo during React refactoring. You can apply this logic when developing hooks or making decisions in complex components.
| Data Type | Does it need UI update on change? | As Hook Dependency? | Core Positioning | | :--- | :--- | :--- | :--- | | State (useState) | Yes | Yes | Driver: Change it to trigger re-render of UI or logic. | | RefObject (useRef) | No | No | Storage: Change it just to "remember" the value, don't want to disturb UI. | | IRefObjectMaybe<T> (generic type) | Depends on input | No (usually not placed) | Config: Provides flexibility, lets external decide whether to drive updates. | | Memo (useMemo) | Yes (when computed result changes) | Yes (memoized computation) | Deriver: Compute from other data, keep reference stable. |
useState)?When the data's "value" is part of the UI, or logic trigger switch.
useSWR, useEffect) immediately re-execute?data).activeKey controlling SWR requests.set or trigger render to take effect, it must be State.useRef)?When the data is pure logic determination or instance reference, and doesn't directly participate in rendering.
boundsRef in your case, only used to determine "whether to send a request".setTimeout ID.inputRef.useState only appears in if statements in your code, never appears in JSX, consider refactoring it to RefObject for performance optimization.IRefObjectMaybe<T> (T | RefObject<T>)?When writing a utility Hook, and want the external caller to decide the "reactive nature" of the data.
ignoreCacheCheck switch.enabled flag.IRefObjectMaybe<T> + unwrapRefObject provides the highest level of flexibility.useMemo)?When the data is a computation result that can be derived from other State/Props, and needs to maintain reference stability.
fillFacilityPointData(batchData?.data), transforming raw API response into format needed by component.useState just to "assemble return object", these should all be replaced with useMemo.useMemo to maintain reference stability.When you see "clunky" code (like that pile of useState), clean it up following these steps:
Find that variable that once changed, everything must follow.
activeKey. When it moves, SWR moves.Find those variables that only write in onSuccess, only read in if.
matchedRangeBounds, triggerThresholdRangeBounds. These are essentially "auxiliary judgment memory", shouldn't be State that drives UI.IRefObjectMaybe<T>Handle switches passed in from parameters.
unwrapRefObject(config) to "unbox" inside Effect.Find values that can be derived from API results.
categories, matchedRangeBounds, triggerThresholdRangeBounds. These are all just parts of batchData, don't need their own useState.useMemo:typescript return useMemo(() => ({ data: fillFacilityPointData(batchData?.data), matchedRangeBounds: batchData?.matchedRangeBounds ?? null, triggerThresholdRangeBounds: batchData?.triggerThresholdRangeBounds ?? null, blockScanRangeBounds: batchData?.blockScanRangeBounds ?? null, categories: batchData?.categories ?? [], error, isLoading, }), [batchData, error, isLoading]);
📚 Complete case reference: React Component Refactoring Patterns - Component extraction, conditional rendering, parameter passing optimization and other practical tips
Refactor scattered error handling logic into unified error handling patterns to improve code robustness and maintainability.
typescript// ❌ Error handling logic scattered, lacks consistency async function fetchUserData(userId: string) { try { const user = await fetchUser(userId); return user; } catch (error) { console.error('Failed to fetch user:', error); return null; } } async function fetchUserProfile(userId: string) { try { const profile = await fetchProfile(userId); return profile; } catch (error) { console.error('Failed to fetch profile:', error); return null; } }
typescript// ✅ Unified error handling pattern interface IApiError { code: string; message: string; details?: unknown; } type TResult<T> = | { success: true; data: T } | { success: false; error: IApiError }; async function safeApiCall<T>( apiCall: () => Promise<T>, context: string ): Promise<TResult<T>> { try { const data = await apiCall(); return { success: true, data }; } catch (error) { const apiError: IApiError = { code: 'API_ERROR', message: `Failed to ${context}`, details: error }; console.error(`${context} error:`, apiError); return { success: false, error: apiError }; } } // Using unified error handling async function fetchUserData(userId: string) { const result = await safeApiCall(() => fetchUser(userId), 'fetch user'); return result.success ? result.data : null; } async function fetchUserProfile(userId: string) { const result = await safeApiCall(() => fetchProfile(userId), 'fetch profile'); return result.success ? result.data : null; }
Refactor complex logic in React components into clearer, more maintainable patterns.
Before: Inline component depends on external variables
typescriptconst BottomListPanel = () => ( <Flex vertical style={{ background: token.colorBgContainer }}> <DataList data={data} onClick={handleClick} /> </Flex> );
After: Independent component with explicit dependencies
typescriptinterface IBottomListPanelProps { data: IDataItem[]; onItemClick: (item: IDataItem) => void; background?: string; } const BottomListPanel = (props: IBottomListPanelProps) => ( <Flex vertical style={{ background: props.background }}> <DataList data={props.data} onClick={props.onItemClick} /> </Flex> );
Before: Repeated JSX structure
typescript{displayMode === 'sidebar' ? ( <Layout.Content>...</Layout.Content> ) : ( <Layout style={{ flex: 1 }}> <Layout.Content>...</Layout.Content> <BottomPanel /> </Layout> )}
After: Abstract layout component
typescriptfunction ConditionalLayout(props: IConditionalLayoutProps) { if (props.displayMode !== EnumDisplayMode.SIDEBAR) { return ( <Layout style={{ flex: 1 }}> {props.children} {props.bottomPanel} </Layout> ); } return <>{props.children}</>; }
Before: Implicit dependency on external variables After: Explicit props passing, improving component independence
Before: Direct token value usage After: Using CSS variables to support dynamic theme switching
Before: Complex single component After: Using component composition instead of inheritance
Before: Complex logic within component After: Extract into custom hooks
Refactor scattered validation logic into reusable validator patterns to improve code reusability and type safety.
typescript// ❌ Validation logic scattered, difficult to reuse function createUser(userData: any) { if (!userData.name || typeof userData.name !== 'string') { throw new Error('Name is required and must be string'); } if (!userData.email || !userData.email.includes('@')) { throw new Error('Valid email is required'); } if (userData.age && (typeof userData.age !== 'number' || userData.age < 0)) { throw new Error('Age must be a positive number'); } // Create user logic... }
typescript// ✅ Reusable validator pattern interface IValidationRule<T> { validate: (value: T) => string | null; required?: boolean; } interface IValidator<T> { rules: IValidationRule<T>[]; validate: (value: T) => string[]; } // Create validator factory function createValidator<T>(rules: IValidationRule<T>[]): IValidator<T> { return { rules, validate: (value: T): string[] => { const errors: string[] = []; for (const rule of rules) { if (!rule.required && (value === undefined || value === null)) { continue; } const error = rule.validate(value); if (error) { errors.push(error); } } return errors; } }; } // Common validation rules const ValidationRules = { required: (message: string): IValidationRule<string> => ({ validate: (value) => !value ? message : null, required: true }), email: (): IValidationRule<string> => ({ validate: (value) => { if (!value) return null; return !value.includes('@') ? 'Invalid email format' : null; } }), positiveNumber: (message: string): IValidationRule<number> => ({ validate: (value) => { if (value === undefined) return null; return typeof value !== 'number' || value < 0 ? message : null; } }) }; // Using validator const userValidator = createValidator({ name: ValidationRules.required('Name is required'), email: [ValidationRules.required('Email is required'), ValidationRules.email()], age: ValidationRules.positiveNumber('Age must be positive') }); interface IUserData { name: string; email: string; age?: number; } function createUser(userData: IUserData) { const errors = [ ...userValidator.validate(userData.name), ...userValidator.validate(userData.email), ...userValidator.validate(userData.age) ]; if (errors.length > 0) { throw new Error(`Validation failed: ${errors.join(', ')}`); } // Create user logic... }
> "State is for triggering, RefObject is for remembering."
IRefObjectMaybe<T>.When refactoring useFacilityPointBlocksData, compressing the originally scattered 5 useState into 1 activeKey (State) + 1 boundsRef (Ref) + 1 useMemo (Derived Data), this is the perfect practice of this guide.
useFacilityPointBlocksData complete refactoring case, demonstrating State + RefObject + useMemo optimization patternBarrel index (also known as "barrel file" or "index barrel") is a pattern where a central index.ts file re-exports multiple modules to simplify import paths.
typescript// ❌ Barrel file pattern (index.ts) // Instead of importing from specific files, you re-export everything through a central file export * from './UserService'; export * from './OrderService'; export * from './ProductService'; // Usage - shorter but opaque import paths import { UserService, OrderService } from './services'; // Imports from index.ts
typescript// ✅ Direct import from source files (recommended) import { UserService } from './services/UserService'; import { OrderService } from './services/OrderService'; import { ProductService } from './services/ProductService';
Barrel files obscure the actual module dependencies, making it difficult to understand what a file truly depends on.
typescript// ❌ With barrel - unclear what dependencies are actually used import { UserService, OrderService } from './services'; // ✅ Without barrel - explicit, clear dependencies import { UserService } from './services/UserService'; import { OrderService } from './services/OrderService';
Barrel exports can interfere with tree shaking in bundlers like Webpack, Rollup, or ESBuild, potentially increasing bundle size because the bundler cannot easily eliminate unused exports.
typescript// Even if you only use UserService, the barrel file may cause // all services to be included in the bundle import { UserService } from './services'; // May include OrderService, ProductService too!
TypeScript needs to process all re-exports even when only one module is needed, which can slow down compilation in large projects.
When a module is removed or renamed, the barrel file must be updated, creating an additional maintenance burden and potential for stale references.
Unless explicitly requested by the user or project requirements, do not create or use barrel index files. All modules should be imported directly from their source paths.
typescript// ❌ Avoid - using barrel index import { UserService } from '../services'; // Ambiguous path // ✅ Recommended - explicit source path import { UserService } from '../services/UserService';
Only use barrel index when explicitly required by:
Even in these cases, carefully weigh the trade-offs.
typescript// ✅ Clear, explicit imports - preferred style import { UserService } from './services/UserService'; import { OrderService } from './services/OrderService'; import { ProductService } from './services/ProductService'; // ✅ For multiple imports from the same module, use namespace import or named imports import * as UserModule from './services/UserService'; import { UserService, IUserRepository } from './services/UserService';
If your project already has widespread barrel files, avoid a big-bang rewrite. Instead, follow a gradual approach:
If the project is new or small enough, you can migrate all at once:
index.ts files that only re-exportUpgrading to TypeScript 6+ from 5.x introduces stricter type checking and module resolution. Refactoring legacy code requires understanding how TS6 handles generics, module paths, and implicit types, prioritizing natural type inference over forceful casting.
Uint8Array vs ArrayBuffer HandlingProblem: TS6 makes Uint8Array a generic Uint8Array<T extends ArrayBufferLike>. It strictly distinguishes between Uint8Array and ArrayBuffer, breaking TS5 code that treated them interchangeably.
.buffer conversions or wrong annotationstypescript// ❌ Wrong return type annotation forcing unnecessary conversions const stringToBuffer = (input: string): ArrayBuffer => { const buf = new Uint8Array(input.length); // ... return buf.buffer; // Treating the symptom, not the disease }; // ❌ Narrow parameters rejecting valid inputs const base64Url = (buf: ArrayBuffer): string => { /* ... */ } base64Url(arr.buffer); // Calling code polluted with .buffer
Remove incorrect type annotations and use union types for parameters.
typescript// ✅ Let TS infer Uint8Array naturally const stringToBuffer = (input: string) => { const buf = new Uint8Array(input.length); return buf; }; // ✅ Broaden parameter types const base64Url = (buf: ArrayBuffer | Uint8Array): string => { /* ... */ }
> Note: APIs like crypto.subtle.digest() accept BufferSource, so Uint8Array works directly without .buffer.
Problem: TS6 strictly checks for type declarations of subpath imports. If a library (like markdown-it) only provides types for its main module, subpath imports fail (e.g., markdown-it/lib/token).
declare module or fake pathstypescript// ❌ Don't declare fake modules for third-party subpaths declare module 'markdown-it/lib/token' { /* ... */ }
Ensure "types": ["package-name"] is in tsconfig.json, and import destructured types from the main entry.
typescript// ✅ Import from main module where types are actually exported import MarkdownIt, { StateBlock, StateInline, Token } from 'markdown-it';
Blob Constructor CastingProblem: BlobPart[] expects BufferSource, but Uint8Array<ArrayBufferLike> is not strictly compatible with ArrayBufferView<ArrayBuffer> due to the .buffer property type differences.
as anytypescriptconst body: (Uint8Array | ArrayBuffer)[] = []; // ... // ✅ Safe bypass: both are valid BlobParts at runtime return new Blob(body as any).arrayBuffer();
http Module Event Callback TypesProblem: Node http.createServer() callbacks show req/res as any because @types/node wasn't loaded properly, causing inference failure.
Do not manually type req/res. Instead, add "node" to compilerOptions.types in tsconfig.json so TS can infer from createServer().
📚 Complete case reference: TypeScript 6 Migration & Source Changes
Other measured skills in the registry, with their headline benchmark lift.