FAQ

TypeScript type inference: how do useDevices / useDevicesProps etc. get full DP types?

By default, multi-device Hooks such as useDevices, useDevicesProps, useDevicesActions, useStructuredDevicesProps, and useStructuredDevicesActions return generic types, so you don't get per-device DP inference. It is recommended to override their return types in your project's typings/sdm.d.ts using declare module, binding each device key to its exact Schema.

Step 1: Define a separate Schema per device

In src/devices/schema.ts, export a Schema for each device PID (role):

src/devices/schema.ts
// src/devices/schema.ts

/** Main device Schema */
export const mainDeviceSchema = [ /* actual DPs */ ] as const;

/** lamp1 Schema (PID: xxx) */
export const lampSchema = [ /* actual DPs */ ] as const;

Step 2: Override multi-device Hook types in typings/sdm.d.ts

Override the MultiDevicesData return type for useDevices; useDevicesProps, useDevicesActions, and the rest will then infer from the same device map:

typings/sdm.d.ts
// typings/sdm.d.ts
export type LampSchema = typeof import('@/devices/schema').lampSchema;
type LampDevice = import('@ray-js/panel-sdk').SmartDeviceModel<LampSchema>;

declare module '@ray-js/panel-sdk' {
  export type LampInstanceData = {
    devInfo: ReturnType<LampDevice['getDevInfo']>;
    dpSchema: ReturnType<LampDevice['getDpSchema']>;
    network: ReturnType<LampDevice['getNetwork']>;
    bluetooth: ReturnType<LampDevice['getBluetooth']>;
  };

  export type MultiDevicesData = {
    main?: SmartDeviceInstanceData;
    lamp1?: LampInstanceData;
    lamp2?: LampInstanceData;
  };
  export function useDevices(): MultiDevicesData;
  export function useDevices<V>(
    selector: (devicesData: MultiDevicesData) => V,
    equalityFn?: (a: V, b: V) => boolean
  ): V;
}

After this override, all multi-device Hooks gain full DP inference at call sites with no other changes, for example:

const devicesData = useDevices();
devicesData.lamp1?.dpSchema.switch_led;   // ✓

const props = useDevicesProps(p => p);
props.lamp1?.switch_led;                   // ✓

Per-page type narrowing when a device key has a different Schema

If a specific page binds a particular key to a different device Schema, define a local type and narrow it with as — other pages are unaffected:

import type { SmartDeviceInstanceData, LampInstanceData } from '@ray-js/panel-sdk';
import type { OtherLampInstanceData } from './types';

type MyPageDevicesData = {
  main?: SmartDeviceInstanceData;
  lamp1?: LampInstanceData;
  lamp2?: OtherLampInstanceData;
};

const devicesData = useDevices() as MyPageDevicesData;