assertHasProperties and assertMutuallyExclusiveOptions
assertHasProperties and assertMutuallyExclusiveOptions (from scenerystack/phet-core) are development-time assertion helpers for validating an object's shape at a call site — the first checks that certain named members exist (anywhere in the prototype chain), the second checks that certain groups of option keys are never supplied together. Both are no-ops in a production build; like the rest of SceneryStack's assert && assert(...) convention, they only run when assertions are enabled, so they should guard invariants, not carry runtime logic.
import { assertHasProperties, assertMutuallyExclusiveOptions } from 'scenerystack/phet-core';assertHasProperties
assertHasProperties( object: unknown, properties: string[] ): voidAsserts that object has an own property or an inherited (prototype-chain) property for every name in properties. Useful for validating a duck-typed dependency (e.g. "this object needs to look like a TColor") without importing its concrete class.
assertHasProperties( someNode, [ 'getOpacity', 'opacity', '_opacity' ] ); // no error if all three exist somewhere in the chain
assertHasProperties( { flower: 2 }, [ 'tree' ] ); // throws: property not defined: treeassertMutuallyExclusiveOptions
assertMutuallyExclusiveOptions( options: object | null | undefined, ...sets: string[][] ): voidAsserts that at most one of the given key-sets has any of its keys present in options — pass one string[] per mutually-exclusive group. options may be null/undefined (treated as "nothing set," so it always passes).
Only one of the provided sets may have any of its keys present at all — using multiple keys within the same set is fine:
assertMutuallyExclusiveOptions( { tree: 1, flower: 2 }, [ 'tree' ], [ 'flower' ] ); // throws - one key used from each of the two sets
assertMutuallyExclusiveOptions( { flower: 2 }, [ 'tree' ], [ 'flower' ] ); // fine - only the second set is used
assertMutuallyExclusiveOptions( { tree: 1, mountain: 2 }, [ 'tree', 'mountain' ], [ 'flower' ] ); // fine - both used keys belong to the first setSummary
| Function | Checks | Throws when |
|---|---|---|
assertHasProperties( object, properties ) | Named members exist (own or inherited) | Any name in properties is missing everywhere in the chain |
assertMutuallyExclusiveOptions( options, ...sets ) | At most one option-key group is used | Keys from more than one of the provided sets are present in options |
Both are guarded by the global assertion flag, not a manual if
Call these directly — don't wrap them in assert && assertHasProperties(...) yourself the way you would with window.assert; these two functions already check internally whether assertions are enabled and no-op if not, matching the convention used by merge and other phet-core runtime checks.