| name | code-typescript |
| description | Typescript/Javascript Standards - Use this skill to learn how to update Typescript or Javascript code. This is the Java coding standard that you MUST apply to all your Typescript code or when you update `.ts` or `.js` files. |
TypeScript Coding Standard - Quick Reference
Type Inference vs Explicit Types
Always explicit for function signatures and returns:
function getUserName(userId: number) {
return 'John';
}
function getUserName(userId: number): string {
return 'John';
}
async function fetchData(url: string): Promise<Data> {
const response = await fetch(url);
return response.json();
}
Null/Undefined Handling Pitfalls
Confusion between optional (?) and union with undefined
interface User {
middleName: string | null;
}
interface User {
middleName?: string;
email: string;
}
function getUserEmail(user: User | null): string {
return user.email;
}
function getUserEmail(user: User | undefined): string {
return user?.email ?? 'unknown@example.com';
}
function process(value: string | undefined): void {
if (value !== undefined) {
console.log(value.toUpperCase());
}
}
Structural Typing Pitfalls
TypeScript uses structural typing (duck typing), not nominal typing
interface Animal {
name: string;
makeSound(): void;
}
interface Vehicle {
name: string;
makeSound(): void;
}
const dog = {
name: 'Buddy',
makeSound() { console.log('Woof!'); }
};
const animal: Animal = dog;
const vehicle: Vehicle = dog;
interface Named {
readonly __brand: 'Named';
name: string;
}
const namedUser: Named = {
__brand: 'Named',
name: 'John',
};
This Context Binding Issues
Arrow functions in classes cause performance issues
class DataProcessor {
data: number[] = [];
process = (): void => {
this.data = [];
};
asyncProcess(): void {
Promise.resolve().then(function () {
this.process();
});
}
}
class DataProcessor {
private data: number[] = [];
process(newData: number[]): void {
this.data = newData;
this.validate();
}
private validate(): void {
console.log('Data validated:', this.data);
}
asyncProcess(): Promise<void> {
return Promise.resolve().then(() => {
this.process([1, 2, 3]);
});
}
}
class DataProcessor {
getCallback(): () => void {
return this.processCallback.bind(this);
}
private processCallback(): void {
}
}
Named Exports Requirement
Default exports are STRICTLY PROHIBITED - use named exports only
export default class UserService { }
export class UserService { }
export interface User { id: number; }
export const DEFAULT_TIMEOUT = 5000;
Disallowed Features
Never use: eval(), debugger, const enum, with keyword, wrapper classes (new Number/String/Boolean), modifying built-in prototypes.
Cognitive Complexity Anti-Pattern
Functions with too many nested conditions (SonarQube catches this)
function processOrder(order: any): void {
if (order.type === 'A') {
if (order.quantity > 10) {
if (order.priority === 'high') {
}
}
}
}
function processOrder(order: Order): void {
if (isHighPriorityBulkOrder(order)) {
applyExpressShipping(order);
}
}
function isHighPriorityBulkOrder(order: Order): boolean {
return order.type === 'A' && order.quantity > 10 && order.priority === 'high';
}
Variable Declaration Rules
Default to const, use let only for reassignment, never use var
Async/Await Common Mistakes
async function fetchData(): Promise<void> {
const data = fetch('/api/data');
console.log(data);
}
async function fetchData(): Promise<Data> {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error('Failed to fetch');
}
return response.json();
}
async function processUser(userId: number): Promise<void> {
const user = await getUser(userId);
console.log(user);
}
async function processUser(userId: number): Promise<void> {
try {
const user = await getUser(userId);
console.log(user);
} catch (error) {
console.error('Failed to process user:', error);
throw error;
}
}
Type Safety Violations
Using any type defeats TypeScript's purpose
function process(data: any): any {
return data.value;
}
interface DataInput {
value: number;
}
function process(data: DataInput): number {
return data.value;
}
function handleUnknown(data: unknown): void {
if (typeof data === 'object' && data !== null && 'value' in data) {
console.log((data as { value: any }).value);
}
}
Complex Type Simplification
Deeply nested types are hard to maintain
type ComplexResponse = {
status: number;
data: {
user: {
id: number;
profile: {
name: string;
email: string;
settings: {
notifications: boolean;
};
};
}[];
};
};
type UserSettings = {
notifications: boolean;
};
type UserProfile = {
name: string;
email: string;
settings: UserSettings;
};
type User = {
id: number;
profile: UserProfile;
};
type ApiResponse<T> = {
status: number;
data: T;
};
type UserApiResponse = ApiResponse<User[]>;
React-Specific Pitfalls
Keys in lists - array indices are anti-pattern
function UserList({ users }): JSX.Element {
return (
<ul>
{users.map((user, index) => (
<li key={index}>{user.name}</li> // Key changes when list reorders!
))}
</ul>
);
}
function UserList({ users }): JSX.Element {
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li> // Stable identifier
))}
</ul>
);
}
Use hooks, not class lifecycle methods
function UserProfile(): JSX.Element {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
return () => { };
}, []);
return <div>{user?.name}</div>;
}
Loop Variable Capture
var in loops with callbacks creates closure bugs
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 100);
}
for (const i of [0, 1, 2]) {
setTimeout(() => {
console.log(i);
}, 100);
}
Security Pitfalls
These will fail SonarQube and code reviews
document.getElementById('content').innerHTML = userInput;
document.getElementById('content').textContent = userInput;
const DB_PASSWORD = 'admin123';
const API_KEY = 'sk_live_abc123';
const DB_PASSWORD = process.env.DB_PASSWORD;
const API_KEY = process.env.API_KEY;
function login(username: string, password: string): void {
console.log(`User ${username} logged in with ${password}`);
}
function login(username: string, password: string): void {
console.log(`User ${username} logged in successfully`);
}
Strict Equality
Always use === and !==, never == or !=
SonarQube Quality Gate Violations
Common catches: Unused variables, unreachable code, missing default cases, code duplication, overly complex functions.
Extract common logic to avoid duplication. Remove unused variables. Keep functions focused.
Document Status: Non-obvious mistakes and SonarQube pitfalls reference
Languages: TypeScript, JavaScript
Focus: Quick-reference for code reviewers and developers