How to use a json property that may or may not exist?

Currently it gives an error:

error: dictionary does not contain key "prop1"

Maybe have a javascript style data.prop1? question mark

This is a general question about dictionaries. When you read a JSON file, you get either a dictionary (like in your case) or an array, depending on the content of the file. See this in the documentation:

JSON objects will be converted into Typst dictionaries, and JSON arrays will be converted into Typst arrays.

So we want to know if a dictionary has a certain key. The way to do that is to check if a str key is in it’s .keys(), like this:

#let mydict = (
  name: "Typst",
  born: 2019,
)

#if "name" in mydict.keys() [
  It has a name.
] else [
  It doesn’t have a name.
]

#if "expiration" in mydict.keys() [
  It has an expiration date.
] else [
  It doesn’t have an expiration date.
]

Have fun Typsting ^_^

By the way, you don’t need to write .keys(), "key" in dictionary already checks whether that is a valid key in the given dictionary.

Additionally, to mirror ?, one can use the at function:

#let x = (a: 5).at("b", default: none) 
#repr(x) // returns 'none'
1 Like

Thanks! I didn’t know that :slightly_smiling_face:

If you need to access nested properties, you can also use default: (:) in the in-between layers, then you can call at() again even if the value didn’t exist:

#let data = (a: 1, c: (d: 2))
data.a = #data.at("a", default: none)\  // 1
data.b = #data.at("b", default: none)\  // none
data.c.d = #data.at("c", default: (:)).at("d", default: none)\  // 2
data.c.e = #data.at("c", default: (:)).at("e", default: none)\  // none
data.f.g = #data.at("f", default: (:)).at("g", default: none)\  // none
3 Likes

Hi @mgholam, don’t forget to tick one of the responses if you got a satisfying answer. The answer you choose should usually be the response that you found most correct/helpful/comprehensive for the question you asked. Thanks!