TypeScript/JavaScript 编码风格¶
此文件使用 TypeScript/JavaScript 特定内容扩展 common/coding-style.md。
类型与接口¶
使用类型使公共 API、共享模型和组件 props 更加明确、可读且可复用。
公共 API¶
- 为导出的函数、共享工具函数和公共类方法添加参数类型和返回值类型
- 对于显而易见的局部变量类型,让 TypeScript 进行推断
- 将重复的内联对象形状提取为命名类型或接口
// 間違い: 明示的な型のないエクスポート関数
export function formatUser(user) {
return `${user.firstName} ${user.lastName}`
}
// 正しい: パブリック API での明示的な型
interface User {
firstName: string
lastName: string
}
export function formatUser(user: User): string {
return `${user.firstName} ${user.lastName}`
}
接口与类型别名¶
- 对于可能被扩展或实现的对象形状,使用
interface - 对于联合类型、交叉类型、元组、映射类型和工具类型,使用
type - 除非出于互操作性需要
enum,否则优先使用字符串字面量联合类型而不是enum
interface User {
id: string
email: string
}
type UserRole = 'admin' | 'member'
type UserWithRole = User & {
role: UserRole
}
避免 any¶
- 在应用代码中避免使用
any - 对外部或不可信输入使用
unknown,并安全地进行类型收窄 - 当值的类型取决于调用方时,使用泛型
// 間違い: any は型安全性を除去する
function getErrorMessage(error: any) {
return error.message
}
// 正しい: unknown は安全なナローイングを強制する
function getErrorMessage(error: unknown): string {
if (error instanceof Error) {
return error.message
}
return 'Unexpected error'
}
React Props¶
- 组件 props 应使用命名
interface或type定义 - 回调 props 应显式添加类型
- 除非有特定原因,否则不要使用
React.FC
interface User {
id: string
email: string
}
interface UserCardProps {
user: User
onSelect: (id: string) => void
}
function UserCard({ user, onSelect }: UserCardProps) {
return <button onClick={() => onSelect(user.id)}>{user.email}</button>
}
JavaScript 文件¶
- 在
.js和.jsx文件中,当类型能提升清晰度且迁移到 TypeScript 不切实际时,使用 JSDoc - 使 JSDoc 与运行时行为保持一致
/**
* @param {{ firstName: string, lastName: string }} user
* @returns {string}
*/
export function formatUser(user) {
return `${user.firstName} ${user.lastName}`
}
不可变性¶
对于不可变更新,使用展开运算符:
interface User {
id: string
name: string
}
// 間違い: ミューテーション
function updateUser(user: User, name: string): User {
user.name = name // ミューテーション!
return user
}
// 正しい: 不変性
function updateUser(user: Readonly<User>, name: string): User {
return {
...user,
name
}
}
错误处理¶
使用 async/await 和 try-catch,并安全地对 unknown 错误进行类型收窄:
interface User {
id: string
email: string
}
declare function riskyOperation(userId: string): Promise<User>
function getErrorMessage(error: unknown): string {
if (error instanceof Error) {
return error.message
}
return 'Unexpected error'
}
const logger = {
error: (message: string, error: unknown) => {
// 本番用ロガー(例: pino や winston)に置き換えてください。
}
}
async function loadUser(userId: string): Promise<User> {
try {
const result = await riskyOperation(userId)
return result
} catch (error: unknown) {
logger.error('Operation failed', error)
throw new Error(getErrorMessage(error))
}
}
输入验证¶
对于基于模式的验证,使用 Zod,并从模式中推断类型:
import { z } from 'zod'
const userSchema = z.object({
email: z.string().email(),
age: z.number().int().min(0).max(150)
})
type UserInput = z.infer<typeof userSchema>
const validated: UserInput = userSchema.parse(input)
Console.log¶
- 不要在生产代码中留下
console.log语句 - 改为使用合适的日志库
- 关于自动检测,请参阅钩子
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC