PageSourceSearch

https://docs.ably.com/component---src-components-layout-mdx-wrappe…eobjects-typing-mdx-5b7c1ae24cb0f903b790.js

js ably.com collected 2026-09-24 15:22:01 UTC 44,374 bytes, 2 lines download raw bytes

1try{let e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},t=(new e.Error).stack;t&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[t]="a686e10d-3986-423a-b14c-5b2ed5df569f",e._sentryDebugIdIdentifier="sentry-dbid-a686e10d-3986-423a-b14c-5b2ed5df569f")}catch(e){}("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{}).SENTRY_RELEASE={id:"4fdb87eed04ecf49489ec6db9b15acde2c687d66"};(self.webpackChunkdocumentation_ably_realtime=self.webpackChunkdocumentation_ably_realtime||[]).push([[843],{59546:function(e,t,n){n.r(t),n.d(t,{default:function(){return V}});var a=n(99694),l=n(30758);function r(e){const t=Object.assign({p:"p",strong:"strong",a:"a",h2:"h2",span:"span",code:"code",ul:"ul",li:"li",h3:"h3",pre:"pre"},(0,a.RP)(),e.components),{Aside:n,If:r,Code:c}=t;return n||o("Aside",!0),c||o("Code",!0),r||o("If",!0),l.createElement(l.Fragment,null,l.createElement(n,{"data-type":"note"},l.createElement(t.p,null,l.createElement(t.strong,null,"Building with LiveObjects?")," Help shape its future by ",l.createElement(t.a,{href:"https://44qpp.share.hsforms.com/2fZobHQA1ToyRfB9xqZYQmQ"},"sharing your use case"),".")),"\n",l.createElement(r,{lang:"java"},l.createElement(t.h2,{id:"type-inference-",style:{position:"relative"}},"Type inference ",l.createElement("a",{id:"type-inference"}),l.createElement(t.a,{href:"#type-inference-","aria-label":"type inference  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"The Java SDK doesn't take user-supplied type parameters to describe the structure of your data. Instead, you infer the type of a value b
1y calling one of the ",l.createElement(t.code,null,"as*")," methods: ",l.createElement(t.code,null,"asLiveMap()"),", ",l.createElement(t.code,null,"asLiveCounter()"),", ",l.createElement(t.code,null,"asString()"),", ",l.createElement(t.code,null,"asNumber()"),", ",l.createElement(t.code,null,"asBoolean()"),", ",l.createElement(t.code,null,"asBinary()"),", ",l.createElement(t.code,null,"asJsonObject()")," or ",l.createElement(t.code,null,"asJsonArray()"),". Each cast returns a typed object that exposes only the operations valid for that type, for example ",l.createElement(t.code,null,"increment()")," on a counter or ",l.createElement(t.code,null,"set()")," on a map."),l.createElement(t.p,null,"The same casts follow different rules depending on the layer you call them on:"),l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"On a ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/path-object?lang=java"},l.createElement(t.code,null,"PathObject")),", casts ",l.createElement(t.strong,null,"never throw"),". A wrong cast only surfaces later, when you use the result."),"\n",l.createElement(t.li,null,"On an ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/instance?lang=java"},l.createElement(t.code,null,"Instance")),", casts ",l.createElement(t.strong,null,"throw immediately")," when the type doesn't match. In return, reads on a typed instance never return ",l.createElement(t.code,null,"null"),"."),"\n"),l.createElement(t.h3,{id:"cast-on-the-path-layer-",style:{position:"relative"}},"Cast on the path layer ",l.createElement("a",{id:"path-layer-casts"}),l.createElement(t.a,{href:"#cast-on-the-path-layer-","aria-label":"cast on the path layer  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"A ",l.createElement(t.code,null,"PathObject")," is a reference to a location, not to a value, so an ",l.createElement(t.code,null,"as*")," cast can't check what is actually stored at the path. The cast always succeeds, and a mismatch only shows up when you use the result:"),l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"Reads, such as ",l.createElement(t.code,null,"value()")," or ",l.createElement(t.code,null,"entries()"),", return ",l.createElement(t.code,null,"null")," or an empty result instead of the expected value."),"\n",l.createElement(t.li,null,"Writes, such as ",l.createElement(t.code,null,"set()")," or ",l.createElement(t.code,null,"increment()"),", return a ",l.createElement(t.code,null,"CompletableFuture")," that c
1ompletes exceptionally with an ",l.createElement(t.code,null,"AblyException"),": error code ",l.createElement(t.code,null,"92007")," when the value at the path doesn't match the inferred type, or ",l.createElement(t.code,null,"92005")," when nothing resolves at the path at all. When you block with ",l.createElement(t.code,null,".join()"),", the failure surfaces as a ",l.createElement(t.code,null,"CompletionException")," whose cause is the ",l.createElement(t.code,null,"AblyException"),"."),"\n"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-java"},'LiveMapPathObject rootObject = channel.object.get().join();\n\n// Infer the \'visits\' path as a LiveCounter; the cast itself never throws\nLiveCounterPathObject visits = rootObject.get("visits").asLiveCounter();\n\nvisits.increment(1).join();\n\n// A typed read returns the value, or null when the path is missing\n// or holds a value of a different type\nString theme = rootObject.at("settings.theme").asString().value(); // String or null\n'))),l.createElement(t.h3,{id:"cast-on-the-instance-layer-",style:{position:"relative"}},"Cast on the instance layer ",l.createElement("a",{id:"instance-layer-casts"}),l.createElement(t.a,{href:"#cast-on-the-instance-layer-","aria-label":"cast on the instance layer  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"An ",l.createElement(t.code,null,"Instance")," wraps a value that has already been resolved, so its type is known at the moment you cast. Because of this, an ",l.createElement(t.code,null,"as*")," cast fails fast: it throws an ",l.createElement(t.code,null,"IllegalStateException")," if the instance is not of the expected type. In return, once the cast succeeds, reads on the typed instance never return ",l.createElement(t.code,null,"null"),":"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-java"},'Instance scoreInstance = rootObject.get("score").instance();\n\nif (scoreInstance != null) {\n    LiveCounterInstance score = scoreInstance.asLiveCounter(); // throws IllegalStateException if not a counter\n\n    System.out.println(score.value()); // non-null Double\n}\n'))),l.createElement(t.h3,{id:"check-the-type-with-gettype-",style:{position:"relative"}},"Check the type with getType() ",l.createElement("a",{id:"get-type"}),l.createElement(t.a,{href:"#check-the-type-with-gettype-","aria-label":"check the type with gettype  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"When you don't know what is stored at a path, call ",l.createElement(t.code,null,"getType()")," before committing to a cast. It returns a ",l.createElement(t.code,null,"ValueType")," enum with one of the following values: ",l.createElement(t.code,null,"STRING"),", ",l.createElement(t.code,null,"NUMBER"),", ",l.createElement(t.code,null,"BOOLEAN"),", ",l.createElement(t.code,null,"BINARY"),", ",l.createElement(t.code,null,"JSON_OBJECT"),", ",l.createElement(t.code,null,"JSON_ARRAY"),", ",l.createElement(t.code,null,"LIVE_MAP"),", ",l.createElement(t.code,null,"LIVE_COUNTER")," or ",l.createElement(t.code,null,"UNKNOWN"),"."),l.createElement(t.p,null,"The result tells you slightly different things on each layer:"),l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"On a ",l.createElement(t.code,null,"PathObject"),", ",l.createElement(t.code,null,"getType()")," returns ",l.createElement(t.code,null,"null")," when nothing resolves at the path. This makes the two cases easy to tell apart: ",l.createElement(t.code,null,"null")," means there is no value at the path, while ",l.createElement(t.code,null,"UNKNOWN")," means a value exists but its type is not recognized."),"\n",l.createElement(t.li,null,"On an ",l.createElement(t.code,null,"Instance"),", ",l.createElement(t.code,null,"getType()")," never returns ",l.createElement(t.code,null,"null"),", be
1cause an instance always wraps an existing value. It also doesn't return ",l.createElement(t.code,null,"UNKNOWN")," in normal operation."),"\n",l.createElement(t.li,null,"A ",l.createElement(t.code,null,"PathObject")," additionally provides ",l.createElement(t.code,null,"exists()"),", a lightweight, best-effort check for whether anything is currently stored at the path."),"\n"),l.createElement(t.p,null,"On a ",l.createElement(t.code,null,"PathObject"),", check the result for ",l.createElement(t.code,null,"null")," before acting on it. Switching directly on a ",l.createElement(t.code,null,"null")," enum throws a ",l.createElement(t.code,null,"NullPointerException"),":"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-java"},'PathObject score = rootObject.get("score");\n\n// getType() returns null when nothing resolves at the path\nValueType type = score.getType();\n\nif (type == null) {\n    System.out.println("Nothing exists at the \'score\' path");\n} else if (type == ValueType.LIVE_COUNTER) {\n    System.out.println(score.asLiveCounter().value());\n} else {\n    System.out.println(score.compactJson());\n}\n'))),l.createElement(t.p,null,"On an ",l.createElement(t.code,null,"Instance"),", the result is never ",l.createElement(t.code,null,"null"),", so you can switch over every ",l.createElement(t.code,null,"ValueType")," value directly:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-java"},'Instance scoreInstance = rootObject.get("score").instance();\n\nif (scoreInstance != null) {\n    switch (scoreInstance.getType()) {\n        case LIVE_COUNTER:\n            System.out.println(scoreInstance.asLiveCounter().value());\n            break;\n        case LIVE_MAP:\n            System.out.println(scoreInstance.asLiveMap().size());\n            break;\n        case STRING:\n        case NUMBER:\n        case BOOLEAN:\n        case BINARY:\n        case JSON_OBJECT:\n        case JSON_ARRAY:\n            // Primitive values are wrapped in read-only primitive instances\n            System.out.println(scoreInstance.compactJson());\n            break;\n        case UNKNOWN:\n            // Never produced by an Instance in normal operation\n            break;\n    }\n}\n'))),l.createElement(t.p,null,"Learn more about type inference on the ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/path-object?lang=java#typing"},"PathObject")," and ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/instance?lang=java#typing"},"Instance")," concept pages.")),"\n",l.createElement(r,{lang:"swift"},l.createElement(t.h2,{id:"type-inference--1",style:{position:"relative"}},"Type inference ",l.createElement("a",{id:"type-inference"}),l.createElement(t.a,{href:"#type-inference--1","aria-label":"type inference  1 permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"The Swift SDK doesn't take user-supplied type parameters to describe the structure of your data. Instead, you work with the type of a value differently on each layer:"),l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"On a ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/path-object?lang=swift"},l.createElement(t.code,null,"PathObject")),", infer the type by calling one of the ",l.createElement(t.code,null,"as*")," methods: ",l.createElement(t.code,null,"asLiveMap()"),", ",l.createElement(t.code,null,"asLiveCounter()")," or ",l.createElement(t.code,null,"asPrimitive()"),". These 
1casts ",l.createElement(t.strong,null,"never throw"),". A wrong cast only surfaces later, when you use the result."),"\n",l.createElement(t.li,null,"On an ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/instance?lang=swift"},l.createElement(t.code,null,"Instance")),", there are no casts at all. ",l.createElement(t.code,null,"Instance")," is an enum, and you discriminate between its cases with an exhaustive ",l.createElement(t.code,null,"switch")," that the compiler checks."),"\n"),l.createElement(t.h3,{id:"cast-on-the-path-layer--1",style:{position:"relative"}},"Cast on the path layer ",l.createElement("a",{id:"path-layer-casts"}),l.createElement(t.a,{href:"#cast-on-the-path-layer--1","aria-label":"cast on the path layer  1 permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"A ",l.createElement(t.code,null,"PathObject")," is a reference to a location, not to a value, so an ",l.createElement(t.code,null,"as*")," cast can't check what is actually stored at the path. The cast always succeeds, and a mismatch only shows up when you use the result:"),l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"Reads, such as ",l.createElement(t.code,null,"value()")," or ",l.createElement(t.code,null,"entries()"),", return ",l.createElement(t.code,null,"nil")," or an empty result instead of the expected value, and never throw for the mismatch."),"\n",l.createElement(t.li,null,"Writes, such as ",l.createElement(t.code,null,"set()")," or ",l.createElement(t.code,null,"increment()"),", throw an ",l.createElement(t.code,null,"ARTErrorInfo")," from a local check inside the awaited call, before any operation is sent: error code ",l.createElement(t.code,null,"92007")," when the value at the path doesn't match the inferred type, or ",l.createElement(t.code,null,"92005")," when nothing resolves at the path at all."),"\n"),l.createElement(t.p,null,"There is a single primitive cast, ",l.createElement(t.code,null,"asPrimitive()"),", whose ",l.createElement(t.code,null,"value()")," returns a ",l.createElement(t.code,null,"Primitive")," enum. When you already know which primitive type you expect, read it with the matching per-case accessor: ",l.createElement(t.code,null,"stringValue()"),", ",l.createElement(t.code,null,"numberValue()"),", ",l.createElement(t.code,null,"boolValue()"),", ",l.createElement(t.code,null,"dataValue()"),", ",l.createElement(t.code,null,"jsonArrayValue()")," or ",l.createElement(t.code,null,"jsonObjectValue()"),". Each returns ",l.createElement(t.code,null,"nil")," when nothing resolves at the path, when the path holds a ",l.createElement(t.code,null,"LiveMap")," or ",l.createElement(t.code,null,"LiveCounter")," rather than a primitive, or when it holds a primitive of a different case."),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-swift"},'let rootObject = try await channel.object.get()\n\n// Infer the \'visits\' path as a LiveCounter; the cast itself never throws\nlet visits = rootObject.get(key: "visits").asLiveCounter()\n\ntry await visits.increment(amount: 1)\n\n// A typed read returns the value, or nil when the path is missing\n// or holds a value of a different type\nlet theme = try rootObject.at(path: "settings.theme").asPrimitive().stringValue() // String or nil\n'))),l.createElement(t.p,null,"Reads are marked ",l.createElement(t.code,null,"try")," only because they throw when LiveObjects cannot be accessed at all: the channel is in the ",l.createElement(t.code,null,"DETACHED")," or ",l.createElement(t.code,null,"FAILED")," state (error code ",l.createElement(t.code,null,"90001"),"), or the channel is missing the ",l.createElement(t.code,null,"object_subscribe")," mode (error code ",l.createElement(t.code,null,"40024"),"). They never throw for a type mismatch or an absent path."),l.createElement(t.p,null,"The per-case accessors are convenience wrappers around ",l.createElement(t.code,null,"value()"),". When you don't know 
1which primitive type to expect, or you need to handle several of them, call ",l.createElement(t.code,null,"value()")," and ",l.createElement(t.code,null,"switch")," over the optional ",l.createElement(t.code,null,"Primitive")," instead. The compiler checks that you handle every case, and the ",l.createElement(t.code,null,".none")," case accounts for an unresolved path as well as one holding a ",l.createElement(t.code,null,"LiveMap")," or ",l.createElement(t.code,null,"LiveCounter"),":"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-swift"},'switch try rootObject.at(path: "settings.theme").asPrimitive().value() {\ncase .string(let string):\n    print(string)     // String, e.g. "dark"\ncase .number(let number):\n    print(number)     // Double\ncase .bool(let bool):\n    print(bool)       // Bool\ncase .data(let data):\n    print(data.count) // Data\ncase .jsonArray(let array):\n    print(array)      // [JSONValue]\ncase .jsonObject(let object):\n    print(object)     // [String: JSONValue]\ncase .none:\n    print("No primitive value at the \'settings.theme\' path")\n}\n'))),l.createElement(t.p,null,"The same accessors exist on the instance layer as properties rather than methods, for example ",l.createElement(t.code,null,"try primitiveInstance.stringValue"),". They are methods on a ",l.createElement(t.code,null,"PathObject")," because each one resolves the path at call time, and properties on an ",l.createElement(t.code,null,"Instance")," because it is already bound to a resolved value. ",l.createElement(t.code,null,"PrimitiveInstance")," also exposes a non-optional ",l.createElement(t.code,null,"value"),", so a ",l.createElement(t.code,null,"switch")," over it has no ",l.createElement(t.code,null,".none")," case."),l.createElement(t.h3,{id:"discriminate-on-the-instance-layer-",style:{position:"relative"}},"Discriminate on the instance layer ",l.createElement("a",{id:"instance-layer-casts"}),l.createElement(t.a,{href:"#discriminate-on-the-instance-layer-","aria-label":"discriminate on the instance layer  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"An ",l.createElement(t.code,null,"Instance")," wraps a value that has already been resolved, so its type is known the moment you obtain it. ",l.createElement(t.code,null,"Instance")," is an enum with three cases — ",l.createElement(t.code,null,".liveMap"),", ",l.createElement(t.code,null,".liveCounter")," and ",l.createElement(t.code,null,".primitive")," — so instead of casting, you discriminate between the cases with an exhaustive ",l.createElement(t.code,null,"switch"),". The compiler checks that you handle every case, and the type mismatch error (code ",l.createElement(t.code,null,"92007"),") that the path layer throws for wrong-typed writes cannot occur from this discrimination. In return, reads on a typed instance never return ",l.createElement(t.code,null,"nil")," for a type mismatch: ",l.createElement(t.code,null,"try map.size")," and ",l.createElement(t.code,null,"try counter.value")," are non-optional."),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-swift"},'switch try rootObject.get(key: "score").instance() {\ncase .liveCounter(let score):\n    print(try score.value) // non-optional Double\ncase .liveMap(let map):\n    print(try map.size)\ncase .primitive(let primitive):\n    print(try primitive.value)\ncase .none:\n    print("Nothing exists at the \'score\' path")\n}\n'))),l.createElement(t.p,null,"Use ",l.createElement(t.code,null,"if case")," when you only need to handle one type:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-swift"},'if case .liveCounter(let score)? = try rootObject.get(key: "score").instance() {\n    print(try score.value) // non-optional Double\n}\n'))),l.createElement(t.h3,{id:"check-a-values-type-",style:{position:"relative"}}
1,"Check a value's type ",l.createElement("a",{id:"get-type"}),l.createElement(t.a,{href:"#check-a-values-type-","aria-label":"check a values type  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"When you don't know what is stored at a path, check its type before committing to a cast. The path layer exposes ",l.createElement(t.code,null,"type()")," (a method) and the instance layer exposes ",l.createElement(t.code,null,"type")," (a property). Both return a ",l.createElement(t.code,null,"ValueType")," enum with one of the following values: ",l.createElement(t.code,null,".string"),", ",l.createElement(t.code,null,".number"),", ",l.createElement(t.code,null,".boolean"),", ",l.createElement(t.code,null,".binary"),", ",l.createElement(t.code,null,".jsonObject"),", ",l.createElement(t.code,null,".jsonArray"),", ",l.createElement(t.code,null,".liveMap"),", ",l.createElement(t.code,null,".liveCounter")," or ",l.createElement(t.code,null,".unknown"),"."),l.createElement(t.p,null,"The result tells you slightly different things on each layer:"),l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"On a ",l.createElement(t.code,null,"PathObject"),", ",l.createElement(t.code,null,"type()")," returns ",l.createElement(t.code,null,"nil")," when nothing resolves at the path. This makes the two cases easy to tell apart: ",l.createElement(t.code,null,"nil")," means there is no value at the path, while ",l.createElement(t.code,null,".unknown")," means a value exists but its type is not recognized."),"\n",l.createElement(t.li,null,"On an ",l.createElement(t.code,null,"Instance"),", the ",l.createElement(t.code,null,"type")," property is non-optional, because an instance always wraps an existing value. It also doesn't return ",l.createElement(t.code,null,".unknown")," in normal operation."),"\n",l.createElement(t.li,null,"A ",l.createElement(t.code,null,"PathObject")," additionally provides ",l.createElement(t.code,null,"exists()"),", a point-in-time check for whether anything is currently stored at the path; it resolves the path at call time."),"\n"),l.createElement(t.p,null,"On a ",l.createElement(t.code,null,"PathObject"),", ",l.createElement(t.code,null,"type()")," returns an optional; check it for ",l.createElement(t.code,null,"nil")," before acting on it:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-swift"},'let score = rootObject.get(key: "score")\n\n// type() returns nil when nothing resolves at the path\nif let type = try score.type() {\n    if type == .liveCounter {\n        print(try score.asLiveCounter().value() ?? 0)\n    } else {\n        print(try score.compactJson() ?? .null)\n    }\n} else {\n    print("Nothing exists at the \'score\' path")\n}\n'))),l.createElement(t.p,null,"On an ",l.createElement(t.code,null,"Instance"),", the ",l.createElement(t.code,null,"type")," property is never ",l.createElement(t.code,null,"nil"),", so you can inspect every ",l.createElement(t.code,null,"ValueType")," value directly:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-swift"},'if let scoreInstance = try rootObject.get(key: "score").instance() {\n    switch scoreInstance.type {\n    case .liveCounter:\n        if case .liveCounter(let counter) = scoreInstance {\n            print(try counter.value)\n        }\n    case .liveMap:\n        if case .liveMap(let map) = scoreInstance {\n            print(try map.size)\n        }\n    case .string, .number, .boolean, .binary, .jsonObject, .jsonArray:\n        // Primitive values are wrapped in read-only primitive instances\n        print(try scoreInstance.compactJson())\n    case .unknown:\n        // Never produced by an Instance in normal operation\n        break\n    }\n}\n'))),l.createElement(t.p,null,"On the write side, ",l.createElement(t.code,null,"set(key:value:)")," takes a ",l.createElement(t.code,null,"LiveMapValue"),". Primitive literals convert automatically through Swift's ",l.createElement(t.code,null,"ExpressibleBy*Literal")," conformances, so passing a ",l.createElement(t.code,null,"String"),", number or ",l.createElement(t.code,null,"Bool")," directly works. To store a nested object, pass a blueprint created with ",l.createElement(t.code,null,"LiveMap.create(entries:)")," or ",l.createElement(t.code,null,"LiveCounter.create(initialCount:)"),", wrapped in the matching ",l.createElement(t.code,null,"LiveMapValue")," 
1case:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-swift"},'// Primitive literals convert automatically to LiveMapValue\ntry await rootObject.set(key: "name", value: "Alice")\n\n// Store a nested object with a blueprint\nlet scores = LiveMap.create(entries: ["total": .liveCounter(LiveCounter.create(initialCount: 0))])\ntry await rootObject.set(key: "scores", value: .liveMap(scores))\n'))),l.createElement(t.p,null,"Learn more about type inference on the ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/path-object?lang=swift#typing"},"PathObject")," and ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/instance?lang=swift#typing"},"Instance")," concept pages.")),"\n",l.createElement(r,{lang:"javascript"},l.createElement(t.p,null,"If you are using TypeScript in your project, you can leverage built-in TypeScript support to ensure type safety and enable autocompletion when working with the channel object."),l.createElement(t.h2,{id:"provide-a-type-for-the-channel-object-",style:{position:"relative"}},"Provide a type for the channel object ",l.createElement("a",{id:"provide"}),l.createElement(t.a,{href:"#provide-a-type-for-the-channel-object-","aria-label":"provide a type for the channel object  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"You can provide a type parameter to the ",l.createElement(t.code,null,"channel.object.get<T>()")," method to specify the expected structure of the channel object:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-javascript"},"import { LiveCounter, LiveMap } from 'ably/liveobjects';\n\n// Define the expected structure of your channel object\ntype RootObject = {\n  visits: LiveCounter;\n  reactions: LiveMap<{\n    likes: LiveCounter;\n    hearts: LiveCounter;\n  }>;\n  settings: LiveMap<{\n    theme: string;\n    notifications: boolean;\n  }>;\n};\n\n// Get a typed PathObject for the channel\nconst rootObject = await channel.object.get<RootObject>();\n"))),l.createElement(t.p,null,"This enables TypeScript to infer the correct types when accessing and mutating objects. TypeScript surfaces the correct set of methods that are expected for the current ",l.createElement(t.code,null,"Instance")," or ",l.createElement(t.code,null,"PathObject")," and infers the correct arguments and return values for all methods:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-javascript"},"// TypeScript knows 'visits' is a LiveCounter\nconst visits = rootObject.get('visits');\nawait visits.increment(5);  // Type-safe\n\n// TypeScript knows the structure of 'reactions'\nconst reactions = rootObject.get('reactions');\nconst likes = reactions.get('likes');\nawait likes.increment(1);  // Type-safe\n\n// TypeScript knows 'theme' is a string\nconst theme = rootObject.get('settings').get('theme');\nconst themeValue: string | undefined = theme.value();\n\n// Type errors are caught at compile time\nawait reactions.set('likes', 'invalid');\n// Error: Argument of type 'string' is not assignable to parameter of type 'LiveCounter'\n"))),l.createElement(t.p,null,"When obtaining ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/concepts/instance"},"Instance")," objects, TypeScript automatically infers the correct instance type:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-javascript"},"type RootObject = {\n  visits: LiveCounter;\n  settings: LiveMap<{\n    theme: string;\n  }>;\n};\n\nconst rootObject = await channel.object.get<RootObject>();\n\nconst visits = rootObject.get('visits').instance();\nawait visits?.increment(1); // TypeScript knows visits is an Instance of a LiveCounter\nconst value: number | undefined = visits?.value(); // TypeScript knows the LiveCounter has a number value\n\nconst settings = rootObject.get('settings').instance();\nawait settings?.set('theme', 'dark'); // TypeScript knows settings is an Instance of a LiveMap\nconst theme: string | undefined = settings?.get('theme')?.value(); // get() returns an Instance for the entry\n"))),l.createElement(t.p,null,"TypeScript also infers the correct instance type when using ",l.createElement(t.a,{href:"https:/docs.ably.com/docs/liveobjects/batch"},"batch operations"),":"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-javascript"},"type RootObject = {\n  visits: LiveCounter;\n  settings: LiveMap<{\n    theme: string;\n  }>;\n};\n\nconst rootObject = await channel.object.get<RootObject>();\n\nawait rootObject.batch((ctx) =>
1 {\n  const visits = ctx.get('visits');\n  visits?.increment(1); // TypeScript knows visits is a LiveCounter\n  const value: number | undefined = visits?.value(); // TypeScript knows the LiveCounter has a number value\n\n  const settings = ctx.get('settings');\n  settings?.set('theme', 'dark'); // TypeScript knows settings is a LiveMap\n  const theme: string | undefined = settings?.get('theme')?.value(); // get() returns a BatchContext for the entry\n});\n"))),l.createElement(t.h2,{id:"define-reusable-types-",style:{position:"relative"}},"Define reusable types ",l.createElement("a",{id:"reusable-types"}),l.createElement(t.a,{href:"#define-reusable-types-","aria-label":"define reusable types  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"You can define and export types for reuse across your application:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-javascript"},"// types/liveobjects.ts\nimport { LiveCounter, LiveMap } from 'ably/liveobjects';\n\nexport type ReactionsType = {\n  likes: LiveCounter;\n  hearts: LiveCounter;\n  fire: LiveCounter;\n};\n\nexport type UserProfileType = {\n  name: string;\n  score: LiveCounter;\n  settings: LiveMap<{\n    theme: string;\n    notifications: boolean;\n  }>;\n};\n\nexport type ChannelObjectType = {\n  reactions: LiveMap<ReactionsType>;\n  users: LiveMap<{\n    [userId: string]: LiveMap<UserProfileType>;\n  }>;\n};\n"))),l.createElement(t.p,null,"Then import and use these types where needed:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-javascript"},"import type { ChannelObjectType } from './types/liveobjects';\n\nconst rootObject = await channel.object.get<ChannelObjectType>();\n\n// Fully typed access\nconst userScore = rootObject\n  .get('users')\n  .get('user123')\n  .get('score');\n\nawait userScore.increment(10);  // Type-safe\n"))),l.createElement(t.h2,{id:"use-per-channel-types-",style:{position:"relative"}},"Use per-channel types ",l.createElement("a",{id:"per-channel"}),l.createElement(t.a,{href:"#use-per-channel-types-","aria-label":"use per channel types  permalink",className:"gatsby-copyable-header after"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}))),l.createElement(t.p,null,"When your application uses multiple channels with different object structures, you can specify different types for each:"),l.createElement(c,null,l.createElement(t.pre,null,l.createElement(t.code,{className:"language-javascript"},"// Define types for different channels\ntype ReactionsChannelObject = {\n  likes: LiveCounter;\n  hearts: LiveCounter;\n};\n\ntype LeaderboardChannelObject = {\n  players: LiveMap<{\n    [playerId: string]: LiveMap<{\n      name: string;\n      score: LiveCounter;\n    }>;\n  }>;\n};\n\n// Get typed objects for different channels\nconst reactionsChannel = client.channels.get('reactions');\nconst reactions = await reactionsChannel.object.get<ReactionsChannelObject>();\n\nconst leaderboardChannel = client.channels.get('leaderboard');\nconst leaderboard = await leaderboardChannel.object.get<LeaderboardChannelObject>();\n\n// Each channel has its own type safety\nawait reactions.get('likes').increment(1);  // Type-safe for reactions\nconst players = leaderboard.get('players');  // Type-safe for leaderboard\n")))))}var c=function(e={}){const{wrapper:t}=Object.assign({},(0,a.RP)(),e.components);return t?l.createElement(t,e,l.createElement(r,e)):r(e)};function o(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}var s=n(62056),i=n(49440),u=n(48734),h=n(70760),d=n(4591),p=n(97453),m=n(62136),y=n(66979),v=n(46149),g=n(84506),E=n(12320),f=n(41785),b=n(88540),w=n(60934),j=n(59150),S=n(80446),k=n(10111),x=n(95333),C=n(10902),O=n(68093),T=n(37281),L=n(63388),I=n(89971),N=n(86070);const M=(0,l.createContext)(void 0),A=({activePage:e,apiKeys:t,children:n,...a})=>{const{sdk:r,setSdk:c}=(()=>{const e=(0,l.useContext)(M);if(!e)throw new Error("useSDK must be used within an SDKProvider");return e})(),o=(0,l.useMemo)(()=>[{term:"RANDOM_CHANNEL_NAME",replacer:d.w}],[]),p=(0,l.useMemo)(()=>{const e=t=>{if("string"==typeof t)return(e=>{let t=e;return o.forEach(({term:e,replacer:n})=>{const a=new RegExp(`{{${e}}}`,"g");t=t.replace(a,n())}),t})(t);if(Array.isArray(t))return t.map(e);if((0,l.isValidElement)(t)){const n=t;return(0,l.cloneElement)(n,n.props,e(n.props.children))}return t};return e(n)},[n,o]),{languageOverride:m,detectedSdkType:y}=(0,l.useMemo)(()=>{const t=e=>{const n=[];
1return l.Children.forEach(e,e=>{if(!(0,l.isValidElement)(e))return;const a=e.props||{},r=(e=>{if(!e)return null;const t=e.match(/language-(\S+)/);return t?t[1]:null})(a.className);r&&n.push(r),a.children&&n.push.apply(n,(0,s.A)(t(a.children)))}),n},n=t(p),a=n.some(e=>e.startsWith("client_")),r=n.some(e=>e.startsWith("agent_"));return a&&e.isDualLanguage?{languageOverride:e.clientLanguage,detectedSdkType:"client"}:r&&e.isDualLanguage?{languageOverride:e.agentLanguage,detectedSdkType:"agent"}:1===n.length&&["html","xml","css","sql","json","shell","text"].includes(n[0])?{languageOverride:n[0],detectedSdkType:void 0}:{languageOverride:void 0,detectedSdkType:void 0}},[p,e.isDualLanguage,e.clientLanguage,e.agentLanguage]),v="client"===y?"Client":"agent"===y?"Agent":null;return(0,N.jsxs)("div",{className:v?"relative":void 0,children:[v&&(0,N.jsx)("span",{className:"absolute top-2 right-2 z-10 text-xs font-medium uppercase tracking-wider text-neutral-700 dark:text-neutral-300",children:v}),(0,N.jsx)(u.A,{...a,lang:m||e.language,sdk:y||r,onChange:(e,t)=>
1{if("client"===y||"agent"===y){const t="client"===y?"client_lang":"agent_lang",n=new URLSearchParams(location.search);return n.set(t,e),void(0,i.oo)(`${location.pathname}?${n.toString()}`)}y||c(null!=t?t:void 0),(0,i.oo)(`${location.pathname}?lang=${e}`)},className:(0,h.A)(a.className,"my-6"),languageOrdering:e.product&&T.x7[e.product]?Object.keys(T.x7[e.product]):[],apiKeys:t,fixed:!1,children:p})]})},_=(e,t,n="")=>null!=e&&e[t]?e[t]:n,H=({children:e,pageContext:t,location:n})=>{var a,r,c,o;const{frontmatter:s}=t,{json_ld:i}=s,{activePage:u}=(0,O.LV)(),{0:h,1:d}=(0,l.useState)(null!==(a=null===(r=t.languages)||void 0===r||null===(c=r.filter(e=>e.startsWith("realtime")||e.startsWith("rest")))||void 0===c||null===(o=c.find(e=>u.language&&e.endsWith(u.language)))||void 0===o?void 0:o.split("_")[0])&&void 0!==a?a:void 0),H=(0,l.useContext)(C.A),V=_(s,"title"),P=_(s,"meta_description","Ably provides a suite of APIs to build, extend, and deliver powerful digital experiences in realtime. Organizations like Toyota, Bloomberg, HubSpot, and Hopin depend on Ably’s platform to offload the growing complexity of business-critical realtime data synchronization at global scale."),R=_(s,"intro"),z=_(s,"meta_keywords"),B=_(s,"identifier"),D=(0,I.G)(V,u.product||"pub_sub"),{canonicalUrl:W}=(0,L.Q)(),U=W(n.pathname),J=(0,x.d)(U),K=(0,l.useMemo)(()=>{if(null!=i){if("object"==typeof i&&!Array.isArray(i))return i;console.warn(`Ignoring invalid json_ld frontmatter on ${n.pathname}: expected an object, received ${Array.isArray(i)?"array":typeof i}.`)}if(!u.languages||u.languages.length<=1)return;const e=u.languages.map(e=>{var t,a;return{"@type":"SoftwareSourceCode",programmingLanguage:null!==(t=null===(a=T.Dq[e])||void 0===a?void 0:a.label)&&void 0!==t?t:e,url:W(`${n.pathname}?lang=${e}`)}});return{"@context":"https://schema.org","@type":"TechArticle",headline:V,description:P,url:U,hasPart:e}},[i,u.languages,V,P,U,n.pathname,W]);(0,m.j)();const X=(0,l.useMemo)(()=>{const e=H.apps&&H.apps.length>0&&H.apps[0].apiKeys.length>0?H.apps:[],t=e.some(({demo:e})=>!e)?e.filter(({demo:e})=>!e):e;return t.length>0?t.flatMap(({name:e,apiKeys:t,demo:n})=>({app:n?"demo":e,keys:t.map(e=>({name:e.name,key:e.whole_key}))})):[{app:"demo",keys:[{name:"demo",key:"demokey:123456"}]}]},[H.apps]);return(0,N.jsxs)(M.Provider,{value:{sdk:h,setSdk:d},children:[(0,N.jsx)(k.p,{title:V,metaTitle:D,canonical:U,description:P,keywords:z,structuredData:K}),(0,N.jsx)("noscript",{children:(0,N.jsxs)("div",{style:{padding:"1rem",margin:"1rem",border:"1px solid #ccc",borderRadius:"4px",backgroundColor:"#f9f9f9"},children:[(0,N.jsx)("p",{children:(0,N.jsx)("strong",{children:"Looking for machine-readable content?"})}),(0,N.jsxs)("ul",{children:[(0,N.jsx)("li",{children:(0,N.jsx)("a",{href:J,children:"View this page as Markdown"})}),(0,N.jsx)("li",{children:(0,N.jsx)("a",{href:"/llms.txt",children:"Browse all documentation pages (llms.txt)"})})]}),(0,N.jsx)("p",{children:(0,N.jsxs)("em",{children:["Tip: Request pages with ",(0,N.jsx)("code",{children:"Accept: text/markdown"})," header or use a recognized LLM user agent to receive markdown directly."]})})]})}),(0,N.jsx)(S.A,{children:(0,N.jsx)(y.XW,{children:(0,N.jsxs)(j.vX,{components:{If:p.A,Code:e=>(0,N.jsx)(A,{activePage:u,apiKeys:X,...e}),Aside:E.A,Table:y.XI,table:y.XI.Root,thead:y.XI.Header,tbody:y.XI.Body,tr:y.XI.Row,th:y.XI.Head,td:y.XI.Cell,Tiles:v.U,MethodSignature:f.y,Tabs:b.t,Tab:b.o,RequiredBadge:w.A},children:[(0,N.jsx)(g.z,{title:V,intro:R,subtitle:B?(0,N.jsx)("code",{className:"inline-flex items-center rounded border-[0.5px] border-neutral-500 dark:border-neutral-800 bg-neutral-100 dark:bg-neutral-1200 px-1.5 py-[3px] font-mono font-medium text-[20px] leading-normal text-neutral-1000 dark:text-neutral-300",children:B}):void 0}),e]})})})]})};function V(e){return l.createElement(H,e,l.createElement(c,e))}}}]);
2//# sourceMappingURL=component---src-components-layout-mdx-wrapper-tsx-content-file-path-src-pages-docs-liveobjects-typing-mdx-5b7c1ae24cb0f903b790.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.