Token导航 LogoToken导航

Agent Skill · 研究检索

meta-design-expressive-typescript(meta 设计 expressive TypeScript)

用于辅助界面设计、视觉规范、排版、配色、布局和交互体验优化。它适合让 Agent 根据产品场景整理页面结构、生成 UI 方案、检查视觉一致性或改进组件层级。使用时需要结合现有品牌、设计系统和用户任务,不应只堆装饰元素;涉及真实页面改动时,应通过截图或浏览器预览检查文本溢出、对齐和响应式表现。

meta-design-expressive-typescript 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为只读;许可证信息还不明确,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 64,698。

总安装 294周安装 12GitHub Stars 5下载 95核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:meta-design-expressive-typescript(meta 设计 expressive TypeScript)
来源仓库:https://github.com/agents-inc/skills
仓库路径:skills/meta-design-expressive-typescript
安装命令:
npx skills add https://github.com/agents-inc/skills --skill meta-design-expressive-typescript
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/agents-inc/skills --skill meta-design-expressive-typescript

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

meta-design-expressive-typescript 用于辅助界面设计、视觉规范和交互体验优化。适合让 Agent 整理页面结构、生成 UI 方案或检查视觉一致性。通过 npx skills add 命令从指定 GitHub 仓库安装并使用该技能。

使用时需结合品牌和设计系统,避免仅堆砌装饰元素;涉及真实页面改动时应通过截图或预览检查表现。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/meta-design-expressive-typescript

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/agents-inc/skills --skill meta-design-expressi…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它标注为只读,先用只读任务试一次,确认行为符合预期再扩大使用范围。

常见问题

6 条

meta-design-expressive-typescript 怎么安装?

在终端执行 npx skills add https://github.com/agents-inc/skills --skill meta-design-expressive-typescr…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

meta-design-expressive-typescript 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

meta-design-expressive-typescript 需要什么权限?

权限级别是只读。该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

meta-design-expressive-typescript 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

meta-design-expressive-typescript 用的人多吗?

公开数据是累计安装 294 次,近一周安装 12 次,下载 95 次,GitHub 5 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

meta-design-expressive-typescript 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。
  • 标注为只读权限,试用阶段不容易误改本地文件。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。
  • 只想先试试效果、不希望它改动本地文件的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
meta-design-expressive-typescript

meta 设计 expressive TypeScript · 本页

2945只读未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Expressive TypeScript

Quick Guide: Write code that communicates its intent without requiring the reader to mentally simulate any of its parts. Apply the two-tier pattern: orchestrators at the top that read like pseudocode, pure functions at the bottom that each do one thing. Extract until the code reads like prose. Use utility libraries only when they genuinely improve readability over plain JS.

<critical_requirements>

CRITICAL: Before Using This Skill

All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

(You MUST structure every non-trivial function as a two-tier orchestrator: guard clauses at the top, named function calls in the middle, assembly at the bottom -- NO inline data transformations in orchestrators)

(You MUST extract any expression that requires mental simulation to understand into a named function or named constant)

(You MUST name functions for WHAT they do, not HOW they do it -- isContentAddition(line) not checkLineStartsWithPlusButNotTriplePlus(line))

(You MUST read the existing code before refactoring -- understand the current structure, then improve it)

(You MUST prefer plain JS methods (.map(), .filter(), .reduce()) over utility libraries when they already read clearly)

</critical_requirements>


Auto-detection: orchestrator pattern, two-tier function, extract function, named predicate, named constant, readability refactor, expressive code, function decomposition, pure function extraction, readable TypeScript, guard clause, early return, flatten conditionals, discriminated union, exhaustive switch, as const satisfies, async orchestrator

When to use:

  • Writing any function that mixes validation, transformation, and assembly logic
  • Refactoring a function where you need to mentally simulate steps to understand the flow
  • Naming predicates, constants, or transforms to communicate intent
  • Deciding whether to use a utility library function or plain JS
  • Decomposing a large function into orchestrator + pure helpers
  • Reviewing code and finding blocks that require mental simulation
  • Flattening deeply nested if/else blocks into guard clauses
  • Writing async functions that orchestrate multiple independent operations
  • Modeling state or events with discriminated unions for exhaustive handling

When NOT to use:

  • Writing simple one-liner functions that are already clear
  • Academic functional programming (monads, functors, Either/Option types)
  • Point-free style where arguments are implicit
  • Over-extracting trivially simple expressions into named functions
  • Performance-critical hot paths where function call overhead matters

Key patterns covered:

  • The two-tier pattern (orchestrator + pure functions)
  • The readability test ("can you understand without simulating?")
  • Named predicates, constants, and transforms
  • Guard clauses: flattening nested conditionals with early returns
  • Discriminated unions + exhaustive switch for type-safe control flow
  • Async orchestrators with Promise.all for independent operations
  • as const satisfies for intent-revealing configuration
  • The extraction decision framework
  • Utility library usage: the 80/20 rule

Detailed Resources

  • examples/core.md - Two-tier pattern, guard clauses, named predicates, named constants, discriminated unions, async orchestrators
  • examples/data-transforms.md - Data transformation patterns, when plain JS is enough, when utility libraries help
  • reference.md - Quick-reference cheat sheet with decision tables

Philosophy

Expressive TypeScript is practical, 80/20 functional programming focused on readability. The core test for any block of code:

"Can someone understand the code's flow without simulating any of its parts?"

If the answer is no, extract the part that requires simulation into a named function or constant. If the answer is yes, leave it alone -- even if it could theoretically be "cleaner."

This is NOT:

  • Monads, functors, or Either/Option types -- those belong in a different skill
  • Point-free style -- implicit arguments obscure intent for most readers
  • Religious functional purity -- side effects in orchestrators are fine; the pure functions underneath are what matter
  • Over-extraction -- three similar lines of code is better than a premature abstraction

The two core ideas:

  1. Orchestrators read like pseudocode. Guard clauses, named function calls, assembly. No inline logic that requires simulation.
  2. Pure functions do one thing. Each has a name that communicates its purpose. Each is independently testable.

When to apply this skill:

  • Any function longer than ~15 lines that mixes concerns
  • Any expression where a reader would need to trace through logic to understand intent
  • Any repeated logic pattern that lacks a descriptive name

When NOT to apply:

  • A single .map() or .filter() that already reads clearly
  • Functions that are already one level of abstraction
  • Trivially simple code where extraction would add noise

Core Patterns

Pattern 1: The Two-Tier Pattern

Every non-trivial function follows the same structure: an orchestrator at the top that reads like pseudocode, calling pure functions at the bottom that each do one thing.

The Orchestrator (Top Tier)
// Orchestrator: reads like a step-by-step plan
function processUserImport(rawData: RawImportData): ImportResult {
  // 1. Guard clauses
  if (!rawData.users.length) {
    return { imported: 0, skipped: 0, errors: [] };
  }

  // 2. Named function calls for each step
  const validated = rawData.users.filter(isValidUser);
  const normalized = validated.map(normalizeUserRecord);
  const deduped = removeDuplicatesByEmail(normalized);
  const { existing, newUsers } = separateExistingUsers(deduped);

  // 3. Assembly
  return {
    imported: newUsers.length,
    skipped: existing.length,
    errors: rawData.users.length - validated.length,
  };
}

Why good: Each line communicates intent through its function name. A reader knows WHAT happens at each step without reading HOW any step works. Guard clauses are at the top. No inline lambdas obscure the flow.

The Pure Functions (Bottom Tier)
// Pure function: one job, named for purpose
function isValidUser(user: RawUser): boolean {
  return user.email.includes("@") && user.name.trim().length > 0;
}

function normalizeUserRecord(user: RawUser): NormalizedUser {
  return {
    email: user.email.toLowerCase().trim(),
    name: user.name.trim(),
    role: user.role ?? DEFAULT_ROLE,
  };
}

function removeDuplicatesByEmail(users: NormalizedUser[]): NormalizedUser[] {
  const seen = new Set<string>();
  return users.filter((user) => {
    if (seen.has(user.email)) return false;
    seen.add(user.email);
    return true;
  });
}

Why good: Each function does one thing, has a descriptive name, and is testable in isolation without mocks or state setup.

Full before/after examples: See examples/core.md for complete orchestrator transformations.

Pattern 2: The Readability Test

Before extracting or refactoring, apply this test to any block of code:

"Can someone understand the code's flow without mentally simulating any of its parts?"
// Fails the readability test -- requires simulation
const result = items
  .filter(
    (item) =>
      item.status === "active" &&
      item.createdAt > cutoffDate &&
      !excludedIds.has(item.id),
  )
  .map((item) => ({
    ...item,
    displayName: item.firstName + " " + item.lastName,
    age: Math.floor((Date.now() - item.birthDate.getTime()) / MS_PER_YEAR),
  }));

Why bad: A reader must mentally execute the filter predicate and the map transform to understand what this produces. The intent is buried in implementation.

// Passes the readability test -- intent is clear from names
const activeItems = items.filter(isActiveAfterCutoff);
const displayRecords = activeItems.map(toDisplayRecord);

Why good: Each step communicates intent. A reader knows the filter selects active items after a cutoff and the map creates display records -- without reading either function's body.

When the Test Says "Leave It Alone"
// Already passes -- don't over-extract
const names = users.map((user) => user.name);
const activeUsers = users.filter((user) => user.isActive);
const total = prices.reduce((sum, price) => sum + price, 0);

Why good: These are already clear single-expression operations. Extracting getName, isActive, or sumPrices would add indirection without improving clarity.


Pattern 3: Named Abstractions

When an expression requires simulation, give it a name that communicates intent.

Named Predicates
// Before: requires simulation to understand filter criteria
const lines = diff.filter(
  (line) => line.startsWith("+") && !line.startsWith("+++"),
);

// After: name communicates intent
const lines = diff.filter(isContentAddition);

function isContentAddition(line: string): boolean {
  return line.startsWith("+") && !line.startsWith("+++");
}

Why good: isContentAddition tells the reader WHAT is being checked. The implementation (startsWith logic) is available but not required to understand the flow.

Named Constants
// Before: magic setup with no context
const skill = createMockSkill("react", {
  conflictsWith: ["vue", "angular"],
  requires: ["typescript"],
});

// After: name communicates purpose
const REACT_WITH_FRAMEWORK_CONFLICTS = createMockSkill("react", {
  conflictsWith: ["vue", "angular"],
  requires: ["typescript"],
});

Why good: When this constant appears in a test, the reader knows its purpose without scrolling to its definition. The name encodes the relevant characteristics.

Named Transforms
// Before: inline formatting logic obscures orchestrator flow
const message = results
  .map((r) =>
    r.success ? `  Installed ${r.name}` : `  Failed ${r.name}: ${r.error}`,
  )
  .join("\n");

// After: name communicates intent
const message = results.map(formatInstallResult).join("\n");

function formatInstallResult(result: InstallResult): string {
  if (result.success) return `  Installed ${result.name}`;
  return `  Failed ${result.name}: ${result.error}`;
}

Why good: The orchestrator reads as "format each result, join with newlines." The formatting details are available but not in the way.

More examples: See examples/core.md for before/after named abstraction patterns.

Pattern 4: The Extraction Decision Framework

Not every expression should be extracted. Use this decision tree:

Does this block require mental simulation to understand?
|-- NO -> Leave it inline. Don't over-extract.
+-- YES -> Does the same logic appear in 2+ places?
    |-- YES -> Extract to shared function (DRY + readability).
    +-- NO -> Would a named function communicate intent the expression doesn't?
        |-- YES -> Extract. The name adds value.
        +-- NO -> Leave it. Extraction would just move code without adding clarity.
Extract: Block Requires Simulation
// Before: simulation required to understand what this produces
const categories = Object.entries(skills).reduce<Record<string, Skill[]>>(
  (acc, [id, skill]) => {
    const cat = skill.category;
    if (!acc[cat]) acc[cat] = [];
    acc[cat].push(skill);
    return acc;
  },
  {},
);

// After: intent is clear from the name
const categories = groupSkillsByCategory(skills);
Don't Extract: Already Clear
// Already clear -- extracting would just move one line
const ids = skills.map((skill) => skill.id);
const hasConflicts = conflicts.length > 0;
const displayName = `${firstName} ${lastName}`;

Why good: These are trivially understandable. A function named getIds, checkHasConflicts, or buildDisplayName would add indirection without improving readability.

Don't Extract: Name Would Be As Complex As Implementation
// Don't extract this:
const isSelected = selectedIds.has(item.id);

// Because the extraction would be:
function isItemSelected(item: Item, selectedIds: Set<string>): boolean {
  return selectedIds.has(item.id);
}
// The name doesn't communicate more than the expression itself

Pattern 5: Guard Clauses (Flatten Nested Conditionals)

Deeply nested if/else blocks force a reader to maintain a mental stack of conditions. Guard clauses invert conditions and return early, keeping the happy path un-nested.

// Flat: each guard exits early, happy path has zero nesting
function getDiscount(user: User, cart: Cart): number {
  if (!user.isActive) return 0;
  if (cart.items.length === 0) return 0;
  if (!user.membership) return STANDARD_DISCOUNT;

  return calculateMemberDiscount(user.membership, cart.total);
}

Why good: Each guard clause handles one concern and exits. The reader never needs to track which else branch they are in. The final line is the happy path, visible at a glance.

Full before/after transformation: See examples/core.md for deeply nested code flattened to guard clauses.

Pattern 6: Discriminated Unions + Exhaustive Switch

When a value can be one of several states, a discriminated union with an exhaustive switch makes the type system enforce that every case is handled. Adding a new variant causes a compile error wherever handling is missing.

type TaskStatus = "pending" | "running" | "completed" | "failed";

function getStatusMessage(status: TaskStatus): string {
  switch (status) {
    case "pending":
      return "Waiting to start";
    case "running":
      return "In progress...";
    case "completed":
      return "Done";
    case "failed":
      return "Something went wrong";
    default: {
      const _exhaustive: never = status;
      return _exhaustive;
    }
  }
}

Why good: The never default guarantees compile-time exhaustiveness. If a fifth status is added to the union, this switch will error until the new case is handled.

Full pattern with discriminated object unions: See examples/core.md for the complete discriminated union pattern.

Pattern 7: Async Orchestrators

The two-tier pattern applies equally to async code. Async orchestrators await named functions in sequence for dependent steps and use Promise.all for independent steps.

async function onboardNewUser(input: OnboardInput): Promise<OnboardResult> {
  const user = await createUserRecord(input);

  // Independent operations -- run in parallel
  const [profile, settings] = await Promise.all([
    initializeProfile(user.id, input.preferences),
    applyDefaultSettings(user.id),
  ]);

  await sendWelcomeEmail(user.email, profile.displayName);

  return { user, profile, settings };
}

Why good: The orchestrator reads as a step-by-step plan. Independent operations are grouped in Promise.all -- signaling to the reader that they don't depend on each other. Each called function is a pure async operation named for its purpose.

Full before/after example: See examples/core.md for an async function decomposed from mixed-concern code.

Pattern 8: as const satisfies for Configuration

When defining static configuration objects, as const satisfies Shape preserves literal types (for autocompletion and typeof/keyof usage) while validating the shape at compile time.

interface RouteConfig {
  path: string;
  auth: boolean;
}

const ROUTES = {
  home: { path: "/", auth: false },
  dashboard: { path: "/dashboard", auth: true },
  settings: { path: "/settings", auth: true },
} as const satisfies Record<string, RouteConfig>;

// Type of ROUTES.home.path is "/", not string
// typeof ROUTES gives you the full literal structure for keyof usage

Why good: The satisfies operator catches typos and missing fields at compile time. The as const preserves exact literal types so downstream code benefits from precise inference. Without satisfies, a typo like {pth: "/"} would silently pass.


<decision_framework>

Decision Framework

When to Apply the Two-Tier Pattern

Is this function > ~15 lines?
|-- NO -> Is it mixing multiple concerns (validate + transform + assemble)?
|   |-- YES -> Apply two-tier pattern
|   +-- NO -> Leave it. Short single-concern functions are fine as-is.
+-- YES -> Does it have clear logical steps?
    |-- YES -> Apply two-tier pattern: orchestrator calls named functions
    +-- NO -> Consider breaking into separate functions by responsibility first

When to Use a Utility Library vs Plain JS

Is this a single .map(), .filter(), or .reduce()?
|-- YES -> Use plain JS. A utility library adds dependency without clarity.
+-- NO -> Is the operation a known concept (group-by, count-by, set-difference)?
    |-- YES -> Does the utility library name match the concept?
    |   |-- YES -> Use the library. groupBy(skills, s => s.category) is
    |   |          clearer than a manual reduce.
    |   +-- NO -> Use plain JS with a named function.
    +-- NO -> Are there 3+ chained transformations?
        |-- YES -> Consider pipe() if intermediate variables would obscure flow.
        +-- NO -> Use plain JS with named intermediate variables.

The 80/20 Rule for Utility Libraries

Use utility functions when the function name IS the documentation:

Use utility libraryUse plain JS
groupBy(items, fn) -- groups by keyitems.map(fn) -- single transform
countBy(items, fn) -- counts per categoryitems.filter(fn) -- single filter
difference(a, b) -- set subtractionitems.find(fn) -- single lookup
partition(items, fn) -- split into twoitems.some(fn) / items.every(fn)
indexBy(items, fn) -- array to lookup mapitems.reduce(fn, init) -- simple sum
pipe(data,...fns) -- 3+ chained opsOne or two chained .map().filter() calls
Full data transformation examples: See examples/data-transforms.md

</decision_framework>


<red_flags>

RED FLAGS

High Priority Issues:

  • An orchestrator function contains inline lambdas longer than a single expression -- extract to named functions
  • A function mixes guard clauses, data transformation, side effects, and return assembly without clear separation
  • Variable names describe implementation (filteredMappedItems) instead of intent (activeDisplayRecords)
  • Code uses .reduce() to build a lookup object when groupBy or indexBy communicates intent directly
  • Deeply nested if/else blocks (3+ levels) instead of guard clauses with early returns
  • A switch on a union type is missing the default: never exhaustiveness check -- adding a new variant will silently fall through

Medium Priority Issues:

  • Using a utility library for a single .map() or .filter() that already reads clearly
  • Extracting trivially simple expressions into named functions (over-extraction)
  • Using pipe() for one or two operations where a variable would be clearer
  • Named constants that are as complex as what they replace

Common Mistakes:

  • Applying point-free style (items.filter(isActive)) when the predicate needs context that point-free obscures -- use an explicit lambda if the predicate needs closure variables
  • Extracting a function that is used exactly once and whose name is just a restatement of the single line it contains
  • Creating a "utils" file that becomes a dumping ground -- group extracted functions by domain, near their callers

Gotchas & Edge Cases:

  • A well-named inline lambda IS a named abstraction: .filter((user) => user.isActive) is already clear because isActive is self-documenting. Don't extract this to a separate function.
  • Utility library pipe() can HURT readability when the reader doesn't know the library -- consider your team's familiarity
  • Guard clauses should return early, not wrap the entire function body in an if block
  • When extracting pure functions, place them at the bottom of the file or in a shared module -- not interspersed with the orchestrators they serve
  • as const satisfies Shape -- order matters. satisfies Shape as const does not work. Lock literals first, then validate shape.
  • In async orchestrators, sequential await on independent operations is a hidden performance bug -- use Promise.all when steps don't depend on each other's results
  • The never exhaustiveness trick requires noUnusedLocals to not flag the variable -- use return _exhaustive instead of just assigning to avoid lint warnings

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

(You MUST structure every non-trivial function as a two-tier orchestrator: guard clauses at the top, named function calls in the middle, assembly at the bottom -- NO inline data transformations in orchestrators)

(You MUST extract any expression that requires mental simulation to understand into a named function or named constant)

(You MUST name functions for WHAT they do, not HOW they do it -- isContentAddition(line) not checkLineStartsWithPlusButNotTriplePlus(line))

(You MUST read the existing code before refactoring -- understand the current structure, then improve it)

(You MUST prefer plain JS methods (.map(), .filter(), .reduce()) over utility libraries when they already read clearly)

Failure to follow these rules will produce code that requires mental simulation to understand -- the exact opposite of expressive TypeScript.

</critical_reminders>

平台分布

Codex

35.9%
按下载量换算34

Claude

27.55%
按下载量换算26

Cursor

17.8%
按下载量换算17

Gemini CLI

8.9%
按下载量换算8

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

只读

该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills