Skip to content

Typescript interface generation doesn't include null for slice or map #3588

Description

@alexjacobson95

Description

When wails' ts generation output type is set to interfaces the resulting interfaces do not mark Golang slices as potentially null-able. This can easily lead to front-end code crashing when using the interfaces because there is no reason to do a null check if the interfaces says the field can't be null. Since the default value for a slice in Go is nil, its quite easy to accidentally pass a nil value to Javascript and crash it.

To Reproduce

  1. wails init -n slicetest
  2. Edit wails.json to use "interfaces" type for ts_generation:
{
  ...
  "bindings": {
    "ts_generation": {
      "outputType": "interfaces"
    }
  }
}
  1. Edit main.go to include a slice as one of the types:
package main

import (
	"embed"

	"github.com/wailsapp/wails/v2"
	"github.com/wailsapp/wails/v2/pkg/options"
)

//go:embed all:frontend/dist
var assets embed.FS

type TestStruct struct {
	TestSlice []int `json:"test_slice"`
}

// App struct
type App struct {
}

func (a *App) NilSlice() TestStruct {
	var t TestStruct
	return t
}

func main() {
	// Create an instance of the app structure
	app := &App{}

	// Create application with options
	err := wails.Run(&options.App{
		Bind: []interface{}{
			app,
		},
	})

	if err != nil {
		println("Error:", err.Error())
	}
}
  1. Run wails generate module
  2. Inspect the resulting models.ts file which uses number[] instead of number[] | null
export namespace main {
	
	export interface TestStruct {
	    test_slice: number[];
	}

}

Expected behaviour

I would expect either the type interface to indicate that a Golang slice could be null when passed to Javascript, or for wails to prevent the Golang Json serializer from converting []int(nil) to null in Json before its passed to JS.

The second option is likely preferred as most of the time it would be annoying to always null check a slice before using it in JS, however that would prevent some use cases. Maybe a setting in the wails.json could be added if we want to go that route.

Screenshots

No response

Attempted Fixes

After looking at this some more, I realized that its because in my project I have the typescript strict setting set true:
https://www.typescriptlang.org/tsconfig/#strict

That causes the strictNullChecks setting to be enabled as well, which is why I am expecting the | null in the interface.
https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#strictnullchecks-on

I think the best solution would be to provide a flag to the typescript generation section in wails.json (something struct: true) to output the correct interfaces for typescript's strict mode.

System Details

# Wails
Version | v2.9.1

# System
┌────────────────────────────────────────────────────────────────────────┐
| OS           | Windows 10 Pro                                          |
| Version      | 2009 (Build: 19045)                                     |
| ID           | 22H2                                                    |
| Go Version   | go1.21.11                                               |
| Platform     | windows                                                 |
| Architecture | amd64                                                   |
| CPU          | Intel(R) Core(TM) i7-6950X CPU @ 3.00GHz                |
| GPU 1        | NVIDIA TITAN X (Pascal) (NVIDIA) - Driver: 31.0.15.4601 |
| GPU 2        | NVIDIA TITAN X (Pascal) (NVIDIA) - Driver: 31.0.15.4601 |
| Memory       | 32GB                                                    |
└────────────────────────────────────────────────────────────────────────┘

# Dependencies
┌───────────────────────────────────────────────────────┐
| Dependency | Package Name | Status    | Version       |
| WebView2   | N/A          | Installed | 126.0.2592.87 |
| Nodejs     | N/A          | Installed | 20.15.0       |
| npm        | N/A          | Installed | 10.7.0        |
| *upx       | N/A          | Available |               |
| *nsis      | N/A          | Available |               |
└─────────────── * - Optional Dependency ───────────────┘

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions