Skip to content

Reaction typings diverge from setReactionsAsync runtime validation in three places #376

Description

@awdr74100

Verified against 1.138.0 (also present in 1.137.0). All three are in the prototype-reaction path, and none of them can be caught by a type checker or a mocked test — the type says one thing and setReactionsAsync says another, so they only surface against a live document.

Runtime error text below is quoted verbatim from setReactionsAsync.


1. EasingFunctionSpring.initialVelocity is rejected

transition: {
  type: 'SMART_ANIMATE',
  duration: 0.4,
  easing: {
    type: 'CUSTOM_SPRING',
    easingFunctionSpring: { mass: 1, stiffness: 200, damping: 20, initialVelocity: 0 },
  },
}
Unrecognized key(s) in object: 'initialVelocity'
  at [0].actions[0].transition.easing.easingFunctionSpring

Dropping initialVelocity succeeds, and a subsequent read returns only { mass, stiffness, damping } — the field never comes back either.

This one is costly in both directions, because all four fields are declared required: sending the three the runtime wants fails a type check (or any schema derived from these typings), and sending four fails Figma.

EasingFunctionSpring has exactly one referent in the file — Easing.easingFunctionSpring — so nothing else depends on the extra field. PhysicalSpring, declared a few lines below, is already exactly the accepted shape:

interface PhysicalSpring {
  readonly mass: number
  readonly stiffness: number
  readonly damping: number
}

2. A hover trigger's deprecatedVersion is rejected

trigger: { type: 'MOUSE_ENTER', delay: 0.25, deprecatedVersion: false }
Unrecognized key(s) in object: 'deprecatedVersion' at [0].trigger

Reading back a MOUSE_ENTER trigger authored today does not include the field, so this looks like it is only ever an output marker for legacy hover triggers. If that is right, the type is still correct for a read and only misleading for a write — marking it as such (or noting it in a doc comment) would be enough.

3. UPDATE_MEDIA_RUNTIME.destinationId is optional in the type, required at runtime

The SKIP_FORWARD | SKIP_BACKWARD and SKIP_TO variants declare destinationId?: string | null, but omitting it is refused:

actions: [{ type: 'UPDATE_MEDIA_RUNTIME', mediaAction: 'SKIP_FORWARD', amountToSkip: 5 }]
Required value missing at [0].actions[0].destinationId

Supplying a valid media destination makes the same call succeed, and all three variants then round-trip intact. Only the first variant (PLAY | PAUSE | …) declares destinationId as required today; the other two appear to need it too.


Found while making prototype reactions round-trip losslessly in Figwright, an MCP server for Figma — every claim above is from a real document, not from reading the .d.ts. Happy to supply more detail on any of them.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions