用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/trycompai/comp --skill code命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | code |
| description | Use when writing TypeScript/React code - covers type safety, component patterns, and file organization |
Source Cursor rule: .cursor/rules/code.mdc.
Original Cursor alwaysApply: false.
any, No Unsafe Casts// ✅ Validate with zod
const TaskSchema = z.object({ id: z.string(), title: z.string() });
const task = TaskSchema.parse(response.data);
// ✅ Use unknown and narrow
const parseResponse = (data: unknown): Task => {
if (!isTask(data)) throw new Error('Invalid');
return data;
};
// ❌ Never
const data: any = fetchData();
const task = response as Task;
const name = user!.name;
// @ts-ignore
// ✅ Generic
const first = <T>(items: T[]): T | undefined => items[0];
// ❌ Any
const first = (items: any[]): any => items[0];
// ✅ Named export, PascalCase file
// TaskCard.tsx
export function TaskCard({ task }: TaskCardProps) { ... }
// ❌ Default export, lowercase
export default function taskCard() { ... }
// ✅ Derived
const completedCount = tasks.filter(t => t.completed).length;
// ❌ Synced state
const [count, setCount] = useState(0);
useEffect(() => {
setCount(tasks.filter(t => t.completed).length);
}, [tasks]);
// External subscriptions
useEffect(() => {
const sub = eventSource.subscribe(handler);
return () => sub.unsubscribe();
}, []);
// DOM measurements
useEffect(() => {
setHeight(ref.current?.getBoundingClientRect().height);
}, []);
import { toast } from 'sonner';
toast.success('Task created');
toast.error('Failed to save');
toast.promise(saveTask(), {
loading: 'Saving...',
success: 'Saved!',
error: 'Failed',
});
app/(app)/[orgId]/tasks/
├── page.tsx # Server component
├── components/
│ └── TaskList.tsx # Client component
├── hooks/
│ └── useTasks.ts # SWR hook
└── data/
└── queries.ts # Server queries
src/components/shared/ # Cross-page components
src/hooks/ # Shared hooks (useApiSWR, useDebounce)
Split large files into focused components.
// ✅ Named
const createTask = ({ title, assigneeId }: CreateTaskParams) => { ... };
createTask({ title: 'Review PR', assigneeId: user.id });
// ❌ Positional
const createTask = (title: string, assigneeId: string) => { ... };
createTask('Review PR', user.id); // What's the 2nd param?
// ✅ Early return
function processTask(task: Task | null) {
if (!task) return null;
if (task.deleted) return null;
return <TaskCard task={task} />;
}
// ❌ Nested
function processTask(task) {
if (task) {
if (!task.deleted) {
return <TaskCard task={task} />;
}
}
return null;
}
// ✅ Prefix with "handle"
const handleClick = () => { ... };
const handleSubmit = (e: FormEvent) => { ... };
const handleTaskCreate = (task: Task) => { ... };
// Interactive elements need keyboard support
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
aria-label="Delete task"
>
<TrashIcon />
</div>
// Form inputs need labels
<label htmlFor="task-name">Task Name</label>
<input id="task-name" type="text" />