#392·goja

Comparing primitive pointers

Author: jmattheisCreated May 26, 2022Updated Jan 8, 2025
Labelsquestion

Goja will convert a go pointer of a primitive type to a JS object, and this prevents this value to be triple equaled in JavaScript. From my point of view this is counterintuitive because I'd expect that *uint16(nil) would be js(undefined or null) and a non nil pointer would be just the primitive value.

I could manually create the object via vm.NewObject(), but this would create boilerplate, which the https://github.com/dop251/goja#mapping-struct-field-and-method-names tries to prevent.

This issue is kinda a duplicate of #377, but I felt like it doesn't really describe the problems with this behavior. Feel free to close the issue regardless, as this probably makes the internal implementation of all primitive types more complex.

Simple example of the behavior:

go
type Thing struct {
	X uint16  `json:"x"`
	Y *uint16 `json:"y"`
}

func main() {
	vm := goja.New()

	vm.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
	x := uint16(5)
	vm.Set("thing", Thing{
		X: x,
		Y: &x,
	})

	fmt.Println("typeof thing.y  ", mustExec(vm, "typeof thing.y").String())
	fmt.Println("typeof thing.x  ", mustExec(vm, "typeof thing.x").String())

	fmt.Println("thing.x === 5  ", mustExec(vm, "thing.x === 5").ToBoolean())
	fmt.Println("thing.y === 5  ", mustExec(vm, "thing.y === 5").ToBoolean())
	fmt.Println("thing.x === thing.y  ", mustExec(vm, "thing.x === thing.y").ToBoolean())

	// typeof thing.y   object
	// typeof thing.x   number
	// thing.x === 5   true
	// thing.y === 5   false
	// thing.x === thing.y   false
}

func mustExec(vm *goja.Runtime, s string) goja.Value {
	v, err := vm.RunScript("myfile", s)
	if err != nil {
		panic(err)
	}
	return v
}