For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/llms-full.txt, and this page is available as Markdown at https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/index.md.
  • 简体中文
  • ts-fsrs
    把间隔重复,组合成你需要的样子。

    一个面向 TypeScript 的类型安全调度框架。从开箱即用的 FSRS-7 开始,再自由组合模型、时间系统与业务规则,不需要切换到另一套 API。

    npm
    yarn
    pnpm
    bun
    deno
    npm install ts-fsrs
    import { 
    function DefaultScheduler<Version extends DefaultSchedulerVersion = "FSRS-7">(options?: DefaultSchedulerOptions<Version>): Promise<DefaultScheduler<Version>>
    type DefaultScheduler<Version extends DefaultSchedulerVersion = "FSRS-7"> = (Version extends "FSRS-7" ? Omit<SchedulerCore<SchedulerCoreEnv<SchedulerEnvFor<FSRS7DefaultSchedulerModel, Chrono<{
        readonly time: SRSSchema<{
            input: Date;
            output: Date;
        }>;
        readonly config: SRSSchema<{
            input: {
                readonly fractionalDays?: boolean | undefined;
            };
            output: {
                readonly fractionalDays: boolean;
            };
        }>;
        readonly fields: {
            readonly card: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                };
            }>;
            readonly revlog: SRSSchema<{
                input: {
                    dueAt: Date;
                    lastReviewAt?: (Date | null) | undefined;
                    reviewTime: Date;
                };
                output: {
                    dueAt: Date;
                    lastReviewAt: Date | null;
                    reviewTime: Date;
                };
            }>;
        };
    }>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>, "definition"> : Omit<...> & {
        ...;
    }) & {
        ...;
    }
    DefaultScheduler
    } from 'ts-fsrs'
    const createdAt = new Date('2026-01-01T00:00:00.000Z') export const now = new Date('2026-01-02T09:30:00.000Z') export const
    const scheduler: DefaultScheduler<"FSRS-7">
    scheduler
    = await
    DefaultScheduler<"FSRS-7">(options?: DefaultSchedulerOptions<"FSRS-7"> | undefined): Promise<DefaultScheduler<"FSRS-7">>
    DefaultScheduler
    ({
    DefaultSchedulerOptions<Version extends DefaultSchedulerVersion = DefaultSchedulerVersion>.desiredRetention?: number | undefined
    desiredRetention
    : 0.9,
    }) export const
    const card: {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        lapses: number;
        scheduledDays: number;
        learningStep: number;
        state: State;
        scheduleStatus: "review" | "new" | "learning";
    }
    card
    =
    const scheduler: DefaultScheduler<"FSRS-7">
    scheduler
    .
    newCard: (options?: ({
        readonly cardId?: string | number | undefined;
    } & {
        readonly now?: Date | undefined;
    }) | undefined) => {
        cardId: string | number;
        stabilityFast: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reps: number;
        lapses: number;
        scheduledDays: number;
        learningStep: number;
        state: State;
        scheduleStatus: "review" | "new" | "learning";
    }
    newCard
    ({
    cardId: 'landing-demo', now: createdAt, }) // One `{ grade, card, revlog }` row per grade — the panel renders exactly this. export const
    const outcomes: PreviewResult<{
        card: {
            cardId: string | number;
            stabilityFast: number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            reps: number;
            lapses: number;
            scheduledDays: number;
            learningStep: number;
            state: State;
            scheduleStatus: "review" | "new" | "learning";
        };
        revlog: {
            cardId: string | number;
            stabilityFast: number;
            stability: number;
            difficulty: number;
            dueAt: Date;
            lastReviewAt: Date | null;
            scheduledDays: number;
            learningStep: number;
            reviewTime: Date;
            state: State;
            scheduleStatus: "review" | "new" | "learning";
            rating: Grade;
        };
    }>
    outcomes
    =
    const scheduler: DefaultScheduler<"FSRS-7">
    scheduler
    .
    preview: (input: {
        readonly card: Readonly<Omit<Readonly<{
            stabilityFast: number;
            stability: number;
            difficulty: number;
        } & {
            dueAt: Date;
            lastReviewAt: Date | null;
        } & {
            readonly cardId: string | number;
            readonly reps: number;
            readonly lapses: number;
            readonly scheduledDays: number;
            readonly learningStep?: number | undefined;
        } & SchedulerCoreFields$1<"review" | "new" | "learning">>, keyof SchedulerCoreFields$1<"review" | "new" | "learning">> & SchedulerCoreFields$1<"review" | "new" | "learning">>;
        readonly now?: Date | undefined;
    }) => PreviewResult<...>
    preview
    ({ card, now })
    稳定性
    3.9221
    难度
    3.5307
    stabilityFast
    3.13768

    与生俱来的类型安全

    同一份 Schema 同时驱动运行时校验与 TypeScript 输入、输出类型推导。

    组合而不必迁移

    从默认调度器开始,在同一内核上逐步替换模型、时间系统与业务规则。

    惰性加载

    惰性预览、按版本代码分割,以及支持 tree-shaking 的子路径导出。

    渐进式 API

    从简单开始,扩展时无需推倒重来。

    直接用默认的 FSRS 调度器,或组合出自己的调度策略,甚至实现一个全新模型 —— 它们共用同一内核。

    01

    使用

    DefaultScheduler 提供带合理默认值的 FSRS 调度器,支持 FSRS-3 至 FSRS-7,默认使用 FSRS-7。DefaultScheduler

    02

    自定义

    选定模型与时间系统,再逐个叠加产品需要的中间件策略。defineScheduler.use(middleware)

    03

    扩展

    当内置能力不够时,自己编写中间件、时间系统或模型。defineMiddlewaredefineChrono

    调度内核

    类型安全

    一个契约,贯穿所有类型。

    Standard Schema 为配置、卡片、复习日志、记忆状态与时间值提供统一的运行时校验与类型契约。

    • 同一份 schema 既在运行时校验,也推导出 TypeScript 类型,两者不可能脱节。
    • 输入卡片始终是 readonly,只有调度结果是可变的。
    • 中间件新增的字段与状态会自动出现在推导类型中。
    StandardSchemaV1zod
    Model
    Chrono
    Middleware
    Readonly<Card>输入
    Mutable<Card>调度结果

    scheduleStatus: 'new' | 'review' | 'suspended'

    内置能力

    开箱即用,按需组合。

    Stats

    为卡片添加并维护复习次数(reps)与遗忘次数(lapses)两个计数器。

    DesiredRetention

    将配置的目标保留率传入间隔计算。

    CostAdr

    根据记忆状态和复习成本调整保留率,用于替换固定目标保留率策略。

    Fuzzing

    以卡片 ID 与复习次数为种子,对间隔施加确定性的抖动。

    LearningSteps

    以分钟、小时或天为单位安排学习与重新学习步骤。

    Leech

    每当卡片的遗忘次数达到所配置阈值的整数倍时,暂停该卡片。

    MaximumInterval

    将最终调度间隔限制在配置的上限内。

    MonotonicInterval

    避免更高评分得到更短的调度间隔。

    ScheduledDays

    保存安排天数及其撤销所需的旧值,启用小数天数时保留小数间隔。

    架构

    模型、时间与策略,彼此独立组合。

    每一个组件都可以单独替换,而调度内核保持不变。

    模型

    • FSRS-3
    • FSRS-4
    • FSRS-4.5
    • FSRS-5
    • FSRS-6
    • FSRS-7
    • defineModel

    Chrono

    • dateChrono
    • numericChrono
    • temporalInstantChrono
    • defineChrono

    中间件

    • learningSteps
    • desiredRetention
    • costAdr
    • fuzzing
    • leech
    • stats
    • defineMiddleware
    Scheduler CorenewCard · preview · review · rollback
    Card + Revlog + ScheduleStatus
    definition
    .use(fuzzing).use(learningSteps)

    use() 返回一个新的 definition;已有的 definition 以及由它创建的调度器都不会被改动。

    性能

    性能是架构的一部分。

    API 围绕惰性求值、代码分割与不可变结果设计。

    按版本代码分割

    DefaultScheduler 会按需加载指定的 FSRS 版本,有助于减少初始加载中不需要的模型代码。

    惰性 preview

    preview() 只会计算你真正遍历到的评分。

    惰性创建 schema

    调度器的 schema 在首次访问时才创建,而不是声明时。

    可 tree-shaking 的导出

    sideEffects 为 false,模型与中间件均以子路径导出提供。

    不可变结果

    review 返回新卡片,不会修改任何输入。

    可回退的复习

    rollback() 能从 revlog 还原上一张卡片,包括中间件字段。

    贡献者

    以开源的方式构建。

    项目中的模型、中间件与各项改进,离不开社区贡献者通过 Pull Request 提供的建议与帮助。

    赞助者

    感谢每一份支持。

    每一份赞助都为 ts-fsrs 的持续维护,以及跟进 FSRS 研究进展提供帮助。

    当前赞助者

    • L-M-Sherlock

    往期赞助者

    • tomerbeil

    成为赞助者

    从 FSRS 开始,构建属于你的调度系统。

    默认调度器可以覆盖常见场景;需要时,可以用不同的模型、时间系统与中间件,组合出自己的调度器。