Loading...
Loading...
Compare original and translation side by side
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noPropertyAccessFromIndexSignature": true,
"exactOptionalPropertyTypes": true
}
}anyunknown// ❌ Bad
function process(data: any) {}
// ✅ Good
function process<T>(data: T): T {}
function process(data: unknown) {
if (typeof data === 'string') {
// Type narrowed to string
}
}type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
function handleResult<T, E>(result: Result<T, E>) {
if (result.ok) {
console.log(result.value); // Type: T
} else {
console.error(result.error); // Type: E
}
}// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noPropertyAccessFromIndexSignature": true,
"exactOptionalPropertyTypes": true
}
}anyunknown// ❌ 不良实践
function process(data: any) {}
// ✅ 最佳实践
function process<T>(data: T): T {}
function process(data: unknown) {
if (typeof data === 'string') {
// 类型收窄为string
}
}type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
function handleResult<T, E>(result: Result<T, E>) {
if (result.ok) {
console.log(result.value); // 类型: T
} else {
console.error(result.error); // 类型: E
}
}type UserId = string & { readonly __brand: 'UserId' };
type Email = string & { readonly __brand: 'Email' };
function createUserId(id: string): UserId {
return id as UserId;
}
// Cannot accidentally mix types
function getUser(id: UserId) {}
getUser('123'); // ❌ Error
getUser(createUserId('123')); // ✅ OKtype HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Route = `/api/${string}`;
type Endpoint = `${HTTPMethod} ${Route}`;
const endpoint: Endpoint = 'GET /api/users'; // ✅type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| { [key: string]: JSONValue };type UserId = string & { readonly __brand: 'UserId' };
type Email = string & { readonly __brand: 'Email' };
function createUserId(id: string): UserId {
return id as UserId;
}
// 不会意外混淆类型
function getUser(id: UserId) {}
getUser('123'); // ❌ 错误
getUser(createUserId('123')); // ✅ 正确type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Route = `/api/${string}`;
type Endpoint = `${HTTPMethod} ${Route}`;
const endpoint: Endpoint = 'GET /api/users'; // ✅type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| { [key: string]: JSONValue };my-typescript-project/
├── src/
│ ├── index.ts # Entry point
│ ├── types/ # Type definitions
│ │ └── index.ts
│ ├── utils/ # Utilities
│ │ └── helpers.ts
│ └── __tests__/ # Tests
│ └── index.test.ts
├── dist/ # Build output
├── tsconfig.json # TypeScript config
├── tsconfig.build.json # Build-specific config
├── package.json
├── .eslintrc.js
└── .prettierrcmy-typescript-project/
├── src/
│ ├── index.ts # 入口文件
│ ├── types/ # 类型定义
│ │ └── index.ts
│ ├── utils/ # 工具函数
│ │ └── helpers.ts
│ └── __tests__/ # 测试文件
│ └── index.test.ts
├── dist/ # 构建输出
├── tsconfig.json # TypeScript配置
├── tsconfig.build.json # 构建专用配置
├── package.json
├── .eslintrc.js
└── .prettierrc{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2023"],
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"exclude": ["**/*.test.ts", "**/__tests__/**"]
}{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2023"],
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"exclude": ["**/*.test.ts", "**/__tests__/**"]
}import { describe, it, expect } from 'vitest';
describe('User service', () => {
it('should create user with valid data', () => {
const user = createUser({
name: 'Alice',
email: 'alice@example.com',
});
expect(user.id).toBeDefined();
expect(user.name).toBe('Alice');
});
});import { expectType } from 'tsd';
const result = getUserById('123');
expectType<Promise<User | null>>(result);import { describe, it, expect } from 'vitest';
describe('User service', () => {
it('should create user with valid data', () => {
const user = createUser({
name: 'Alice',
email: 'alice@example.com',
});
expect(user.id).toBeDefined();
expect(user.name).toBe('Alice');
});
});import { expectType } from 'tsd';
const result = getUserById('123');
expectType<Promise<User | null>>(result);undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefined// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@/types/*": ["src/types/*"],
"@/utils/*": ["src/utils/*"]
}
}
}// Now use clean imports
import { helper } from '@/utils/helper';
import type { User } from '@/types';// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@/types/*": ["src/types/*"],
"@/utils/*": ["src/utils/*"]
}
}
}// 现在可以使用简洁的导入方式
import { helper } from '@/utils/helper';
import type { User } from '@/types';type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
interface RequestOptions<T = unknown> {
method: HTTPMethod;
body?: T;
headers?: Record<string, string>;
}
class APIClient {
constructor(private baseUrl: string) {}
async request<TResponse, TBody = unknown>(
endpoint: string,
options: RequestOptions<TBody>
): Promise<TResponse> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: options.method,
headers: {
'Content-Type': 'application/json',
...options.headers,
},
body: options.body ? JSON.stringify(options.body) : undefined,
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
}
async get<T>(endpoint: string): Promise<T> {
return this.request<T>(endpoint, { method: 'GET' });
}
async post<TResponse, TBody = unknown>(
endpoint: string,
body: TBody
): Promise<TResponse> {
return this.request<TResponse, TBody>(endpoint, {
method: 'POST',
body,
});
}
}
// Usage with full type safety
interface User {
id: string;
name: string;
email: string;
}
const api = new APIClient('https://api.example.com');
const user = await api.get<User>('/users/123'); // Type: Usertype HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
interface RequestOptions<T = unknown> {
method: HTTPMethod;
body?: T;
headers?: Record<string, string>;
}
class APIClient {
constructor(private baseUrl: string) {}
async request<TResponse, TBody = unknown>(
endpoint: string,
options: RequestOptions<TBody>
): Promise<TResponse> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: options.method,
headers: {
'Content-Type': 'application/json',
...options.headers,
},
body: options.body ? JSON.stringify(options.body) : undefined,
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
}
async get<T>(endpoint: string): Promise<T> {
return this.request<T>(endpoint, { method: 'GET' });
}
async post<TResponse, TBody = unknown>(
endpoint: string,
body: TBody
): Promise<TResponse> {
return this.request<TResponse, TBody>(endpoint, {
method: 'POST',
body,
});
}
}
// 全类型安全的使用示例
interface User {
id: string;
name: string;
email: string;
}
const api = new APIClient('https://api.example.com');
const user = await api.get<User>('/users/123'); // 类型: User// package.json
{
"name": "my-library",
"version": "1.0.0",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
},
"files": ["dist"],
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts"
}
}// package.json
{
"name": "my-library",
"version": "1.0.0",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
},
"files": ["dist"],
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts"
}
}anyany// Bad
function process(data: any) {
return data.value; // No type safety
}
// Good
function process<T extends { value: unknown }>(data: T) {
return data.value; // Type-safe
}// 不良实践
function process(data: any) {
return data.value; // 无类型安全
}
// 最佳实践
function process<T extends { value: unknown }>(data: T) {
return data.value; // 类型安全
}// Bad - Lies to compiler
const user = data as User;
// Good - Validate first
function isUser(data: unknown): data is User {
return (
typeof data === 'object' && data !== null && 'id' in data && 'name' in data
);
}
if (isUser(data)) {
// data is User here
}// 不良实践 - 向编译器传递错误信息
const user = data as User;
// 最佳实践 - 先验证类型
function isUser(data: unknown): data is User {
return (
typeof data === 'object' && data !== null && 'id' in data && 'name' in data
);
}
if (isUser(data)) {
// 此处data的类型为User
}// Bad - Disabling strict checks
{
"compilerOptions": {
"strict": false // ❌
}
}
// Good - Enable all strict checks
{
"compilerOptions": {
"strict": true, // ✅
"noUncheckedIndexedAccess": true
}
}// 不良实践 - 禁用严格检查
{
"compilerOptions": {
"strict": false // ❌
}
}
// 最佳实践 - 启用所有严格检查
{
"compilerOptions": {
"strict": true, // ✅
"noUncheckedIndexedAccess": true
}
}import { readFile } from 'node:fs/promises';
async function loadConfig(): Promise<Config> {
const data = await readFile('./config.json', 'utf-8');
return JSON.parse(data) as Config;
}import { readFile } from 'node:fs/promises';
async function loadConfig(): Promise<Config> {
const data = await readFile('./config.json', 'utf-8');
return JSON.parse(data) as Config;
}interface Props {
user: User;
onUpdate: (user: User) => void;
}
export function UserCard({ user, onUpdate }: Props) {
return (
<div>
<h2>{user.name}</h2>
<button onClick={() => onUpdate(user)}>Update</button>
</div>
);
}interface Props {
user: User;
onUpdate: (user: User) => void;
}
export function UserCard({ user, onUpdate }: Props) {
return (
<div>
<h2>{user.name}</h2>
<button onClick={() => onUpdate(user)}>Update</button>
</div>
);
}import express, { Request, Response } from 'express';
const app = express();
app.get('/users/:id', (req: Request<{ id: string }>, res: Response) => {
const userId = req.params.id; // Type: string
// ...
});import express, { Request, Response } from 'express';
const app = express();
app.get('/users/:id', (req: Request<{ id: string }>, res: Response) => {
const userId = req.params.id; // 类型: string
// ...
});anyunknownsatisfiesanyunknownsatisfies