@mega-yfue/eufy-sdk / Surface
Type Alias: Surface<M>
type Surface<M> = { readonly [K in keyof M as K extends ValueKeys<M> ? K : never]?: ReadValue<M[K]> } & { [K in keyof M as K extends Exclude<WritableKeys<M>, ConditionalKeys<M>> & string ? SetterName<K, M[K]> : never]: (value: WriteValue<M[K]>) => Promise<void> } & { [K in keyof M as K extends Extract<WritableKeys<M>, ConditionalKeys<M>> & string ? SetterName<K, M[K]> : never]?: (value: WriteValue<M[K]>) => Promise<void> } & { [K in keyof M as K extends Exclude<ActionKeys<M>, ConditionalKeys<M>> & string ? K : never]: () => Promise<void> } & { [K in keyof M as K extends Extract<ActionKeys<M>, ConditionalKeys<M>> & string ? K : never]?: () => Promise<void> } & { [K in keyof M as K extends Exclude<MethodKeys<M>, ConditionalKeys<M>> ? K : never]: M[K] extends MethodMember<infer F> ? F : never } & { [K in keyof M as K extends Extract<MethodKeys<M>, ConditionalKeys<M>> ? K : never]?: M[K] extends MethodMember<infer F> ? F : never } & { [K in keyof M as K extends ProvidedKeys<M> ? K : never]?: M[K] extends { provided: (args: never[]) => infer F } ? Exclude<F, false | undefined> : never };The bound dev.<cap>() object, derived from the member table.
Getters are optional because they are evidence-gated at runtime — the device may never have reported the param. A write is offered on any device with the capability unless the member gates it.
Every branch maps over keyof M and filters in the as clause rather than over a pre-filtered key union. The two describe the same keys, but only the first is HOMOMORPHIC, and a homomorphic mapped type carries each member's JSDoc through to the projection — so hovering dev.lock().lock() in an editor shows what the member table says about it. Mapping over [K in MethodKeys<M>] silently drops it, which costs the derived surface the one thing a hand-written *Actions type still had over it.
The provider branch matches STRUCTURALLY on the built function rather than on ProvidedMember<P, F>: the provider sits in a contravariant position, so a nominal match against the union's provider type never succeeds. A builder's falsy half is its way of DECLINING, which the optional ? already says, so it is stripped rather than leaking into what a caller holds after the guard.
Type Parameters
M
M extends Members