No, it's generally not a good practice to always explicitly return nullinstead of letting functions return undefinedimplicitly in TypeScript. Here's why:
Problems with Always Returning null
1. Inconsistent with JavaScript Conventions
// Against JS/TS conventions
function findUser(id: number): User | null {
const user = users.get(id);
if (!user) return null; // ❌ Forces null when undefined is conventional
return user;
}
// More conventional
function findUser(id: number): User | undefined {
return users.get(id); // ✅ Returns undefined naturally
}
2. Fights Language Semantics
// Unnecessarily verbose
function processValue(value: string): string | null {
if (!value) return null;
return value.trim(); // ❌ Converts empty string to null
}
// More natural
function processValue(value: string): string | undefined {
if (!value) return undefined;
return value.trim();
}
When to Use Each
Use undefinedfor:
-
Missing/Optional Values
-
Function Parameters (not provided)
-
Object Properties (not defined)
-
Array Elements (not present)
// Natural undefined usage
interface Config {
timeout?: number; // Naturally undefined if not provided
}
const getUser = (id: number): User | undefined => {
return database.users[id]; // Naturally undefined if not found
};
Use nullfor:
-
Explicit Empty/Null States
-
Database NULL Values
-
Intentional Absence
// Appropriate null usage
interface User {
name: string;
deletedAt: Date | null; // Explicit "soft delete" state
}
function fetchData(): Promise<Data | null> {
if (offlineMode) return null; // Explicit "unavailable" state
}
Better Practice: Be Consistent
Option 1: Prefer undefined(Recommended)
// Consistent undefined approach
class ApiService {
private cache = new Map<string, Data>();
getData(key: string): Data | undefined {
return this.cache.get(key); // Natural undefined
}
findUser(email: string): User | undefined {
return users.find(u => u.email === email); // Natural undefined
}
}
Option 2: Prefer null(If You Must)
// If you choose null, be consistent everywhere
class ApiService {
private cache = new Map<string, Data>();
getData(key: string): Data | null {
return this.cache.get(key) ?? null; // Convert undefined to null
}
findUser(email: string): User | null {
return users.find(u => u.email === email) ?? null;
}
}
TypeScript Benefits of Using undefined
1. Better Type Inference
// TypeScript understands optional/undefined naturally
interface User {
id: number;
avatar?: string; // Implicitly string | undefined
}
const user: User = { id: 1 };
console.log(user.avatar); // Type: string | undefined
2. Optional Chaining Works Naturally
// Works seamlessly with undefined
const userName = user?.profile?.name; // Type: string | undefined
// Versus null (requires conversion)
const userName = user?.profile?.name ?? null; // Extra step needed
3. Default Parameters
// undefined triggers default values naturally
function greet(name: string = "Anonymous") {
return `Hello, ${name}!`;
}
greet(undefined); // "Hello, Anonymous!"
greet(null); // "Hello, null!" 😕
When to Definitely Use null
// Use null for explicit "empty" states
interface FormState {
values: Record<string, string>;
errors: Record<string, string> | null; // null = not yet validated
submittedAt: Date | null; // null = never submitted
}
// Use null for database NULL values
interface Product {
id: number;
categoryId: number | null; // NULL in database = no category
}
Recommendation
Prefer undefined for most cases because:
-
It's the language's natural "missing value"
-
Better tooling support
-
More predictable behavior
-
Less boilerplate code
Use nullsparingly for explicit "empty state" semantics where the distinction from "not set" matters.
The worst practice is mixing them inconsistently. Choose one approach and stick with it throughout your codebase.
743

被折叠的 条评论
为什么被折叠?



