diff --git a/v3/internal/generator/render/create.go b/v3/internal/generator/render/create.go index 8a7880390..1332345d1 100644 --- a/v3/internal/generator/render/create.go +++ b/v3/internal/generator/render/create.go @@ -213,17 +213,22 @@ func (m *module) PostponedCreates() []string { m.postponedCreates.Iterate(func(key types.Type, value any) { pp := value.(*postponed) - pre := "" + pre, post := "", "" if pp.params != "" { - pre = pp.params + " => " + if m.TS { + pre = createParamRegex.ReplaceAllString(pp.params, "${0}: any") + " => " + } else { + pre = "/** @type {(...args: any[]) => any} */(" + pp.params + " => " + post = ")" + } } switch t := key.(type) { case *types.Array, *types.Slice: - result[pp.index] = fmt.Sprintf("%s$Create.Array(%s)", pre, m.JSCreateWithParams(t.(interface{ Elem() types.Type }).Elem(), pp.params)) + result[pp.index] = fmt.Sprintf("%s$Create.Array(%s)%s", pre, m.JSCreateWithParams(t.(interface{ Elem() types.Type }).Elem(), pp.params), post) case *types.Map: - result[pp.index] = fmt.Sprintf("%s$Create.Map($Create.Any, %s)", pre, m.JSCreateWithParams(t.Elem(), pp.params)) + result[pp.index] = fmt.Sprintf("%s$Create.Map($Create.Any, %s)%s", pre, m.JSCreateWithParams(t.Elem(), pp.params), post) case *types.Named: if !collect.IsClass(key) { @@ -231,23 +236,24 @@ func (m *module) PostponedCreates() []string { // require an indirect assignment to break cycles. // Typescript cannot infer the return type on its own: add hints. - cast, returnType := "", "" + cast, argType, returnType := "", "", "" if m.TS { + argType = ": any[]" returnType = ": any" } else { cast = "/** @type {(...args: any[]) => any} */" } result[pp.index] = fmt.Sprintf(` -%s(function $$initCreateType%d(...args)%s { +%s(function $$initCreateType%d(...args%s)%s { if ($$createType%d === $$initCreateType%d) { - $$createType%d = %s%s; + $$createType%d = %s%s%s; } return $$createType%d(...args); })`, - cast, pp.index, returnType, + cast, pp.index, argType, returnType, pp.index, pp.index, - pp.index, pre, m.JSCreateWithParams(t.Underlying(), pp.params), + pp.index, pre, m.JSCreateWithParams(t.Underlying(), pp.params), post, pp.index, )[1:] // Remove initial newline. @@ -280,11 +286,12 @@ func (m *module) PostponedCreates() []string { } builder.WriteString(")") } + builder.WriteString(post) result[pp.index] = builder.String() case *types.Pointer: - result[pp.index] = fmt.Sprintf("%s$Create.Nullable(%s)", pre, m.JSCreateWithParams(t.Elem(), pp.params)) + result[pp.index] = fmt.Sprintf("%s$Create.Nullable(%s)%s", pre, m.JSCreateWithParams(t.Elem(), pp.params), post) case *types.Struct: info := m.collector.Struct(t) @@ -311,11 +318,12 @@ func (m *module) PostponedCreates() []string { builder.WriteRune('\n') } builder.WriteString("})") + builder.WriteString(post) result[pp.index] = builder.String() default: - result[pp.index] = pre + "$Create.Any" + result[pp.index] = pre + "$Create.Any" + post } }) diff --git a/v3/internal/generator/render/info.go b/v3/internal/generator/render/info.go index 7cd95a3f6..b3305e3f8 100644 --- a/v3/internal/generator/render/info.go +++ b/v3/internal/generator/render/info.go @@ -1,6 +1,7 @@ package render import ( + "regexp" "strings" "github.com/wailsapp/wails/v3/internal/generator/collect" @@ -26,6 +27,9 @@ type modelInfo struct { } } +// createParamRegex must match type parameter creation strings as generated by [modelinfo]. +var createParamRegex = regexp.MustCompile(`\$\$createParam[^\s,)]*`) + // modelinfo gathers and returns useful information about the given model. func modelinfo(model *collect.ModelInfo, useInterfaces bool) (info modelInfo) { info.HasValues = len(model.Values) > 0 diff --git a/v3/internal/generator/render/templates/models.js.tmpl b/v3/internal/generator/render/templates/models.js.tmpl index 4d12429d0..5fe0db83c 100644 --- a/v3/internal/generator/render/templates/models.js.tmpl +++ b/v3/internal/generator/render/templates/models.js.tmpl @@ -9,7 +9,7 @@ {{if not $useInterfaces}} // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports -import {Create as $Create} from "{{js $runtime}}"; +import { Create as $Create } from "{{js $runtime}}"; {{end -}} {{range $imports.External}} // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/v3/internal/generator/render/templates/models.ts.tmpl b/v3/internal/generator/render/templates/models.ts.tmpl index e82e7311a..d5ec2a971 100644 --- a/v3/internal/generator/render/templates/models.ts.tmpl +++ b/v3/internal/generator/render/templates/models.ts.tmpl @@ -8,7 +8,7 @@ {{if not $useInterfaces}} // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports -import {Create as $Create} from "{{js $runtime}}"; +import { Create as $Create } from "{{js $runtime}}"; {{end -}} {{range $imports.External}} // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/v3/internal/generator/render/templates/service.js.tmpl b/v3/internal/generator/render/templates/service.js.tmpl index bde8ad188..f71e055bf 100644 --- a/v3/internal/generator/render/templates/service.js.tmpl +++ b/v3/internal/generator/render/templates/service.js.tmpl @@ -22,7 +22,7 @@ {{end}} // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports -import {Call as $Call{{if not $useInterfaces}}, Create as $Create{{end -}} } from "{{js $runtime}}"; +import { Call as $Call, CancellablePromise as $CancellablePromise{{if not $useInterfaces}}, Create as $Create{{end}} } from "{{js $runtime}}"; {{range $imports.External}} // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports @@ -46,7 +46,7 @@ import * as $models from "./{{js $models}}"; {{- range $i, $param := .Params}} * @param { {{- $module.JSType .Type}}{{if .Variadic}}[]{{end -}} } {{jsparam $i .}} {{- end}} - * @returns {Promise< + * @returns {$CancellablePromise< {{- if eq 0 (len .Results) -}} void {{- else if eq 1 (len .Results)}} @@ -56,7 +56,7 @@ import * as $models from "./{{js $models}}"; {{- if gt $i 0}}, {{end}} {{- $module.JSType $result}} {{- end}}] - {{- end}}> & { cancel(): void }} + {{- end}}>} */ {{if not .Internal}}export {{end}}function {{.Name}}({{range $i, $param := .Params -}} {{- if gt $i 0}}, {{end}} @@ -64,14 +64,14 @@ import * as $models from "./{{js $models}}"; {{- jsparam $i .}} {{- end}}) { {{- if $useNames}} - let $resultPromise = /** @type {any} */($Call.ByName("{{js .FQN}}" + return $Call.ByName("{{js .FQN}}" {{- else}} - let $resultPromise = /** @type {any} */($Call.ByID({{.ID}} - {{- end}}{{range $i, $param := .Params}}, {{jsparam $i .}}{{end}})); - {{- if or $useInterfaces (not .Results) ($module.SkipCreate .Results)}} - return $resultPromise; - {{- else}} - let $typingPromise = /** @type {any} */($resultPromise.then(($result) => { + return $Call.ByID({{.ID}} + {{- end}}{{range $i, $param := .Params}}, {{jsparam $i .}}{{end}}) + {{- if or $useInterfaces (not .Results) ($module.SkipCreate .Results) -}} + ; + {{- else -}} + .then(/** @type {($result: any) => any} */(($result) => { {{- if eq 1 (len .Results)}} return {{$module.JSCreate (index .Results 0)}}($result); {{- else}} @@ -83,8 +83,6 @@ import * as $models from "./{{js $models}}"; return $result; {{- end}} })); - $typingPromise.cancel = $resultPromise.cancel.bind($resultPromise); - return $typingPromise; {{- end}} } {{end}} diff --git a/v3/internal/generator/render/templates/service.ts.tmpl b/v3/internal/generator/render/templates/service.ts.tmpl index 9a2f0cd31..4db90fe60 100644 --- a/v3/internal/generator/render/templates/service.ts.tmpl +++ b/v3/internal/generator/render/templates/service.ts.tmpl @@ -21,7 +21,7 @@ {{end}} // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports -import {Call as $Call{{if not $useInterfaces}}, Create as $Create{{end -}} } from "{{js $runtime}}"; +import { Call as $Call, CancellablePromise as $CancellablePromise{{if not $useInterfaces}}, Create as $Create{{end}} } from "{{js $runtime}}"; {{range $imports.External}} // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports @@ -49,7 +49,7 @@ import * as $models from "./{{js $models}}"; {{- if gt $i 0}}, {{end}} {{- if .Variadic}}...{{end}} {{- jsparam $i .}}: {{$module.JSType .Type}}{{if .Variadic}}[]{{end}} -{{- end}}): Promise< +{{- end}}): $CancellablePromise< {{- if eq 0 (len .Results) -}} void {{- else if eq 1 (len .Results)}} @@ -59,16 +59,16 @@ import * as $models from "./{{js $models}}"; {{- if gt $i 0}}, {{end}} {{- $module.JSType $result}} {{- end}}] - {{- end}}> & { cancel(): void } { + {{- end}}> { {{- if $useNames}} - let $resultPromise = $Call.ByName("{{js .FQN}}" + return $Call.ByName("{{js .FQN}}" {{- else}} - let $resultPromise = $Call.ByID({{.ID}} - {{- end}}{{range $i, $param := .Params}}, {{jsparam $i .}}{{end}}) as any; - {{- if or $useInterfaces (not .Results) ($module.SkipCreate .Results)}} - return $resultPromise; - {{- else}} - let $typingPromise = $resultPromise.then(($result: any) => { + return $Call.ByID({{.ID}} + {{- end}}{{range $i, $param := .Params}}, {{jsparam $i .}}{{end}}) + {{- if or $useInterfaces (not .Results) ($module.SkipCreate .Results) -}} + ; + {{- else -}} + .then(($result: any) => { {{- if eq 1 (len .Results)}} return {{$module.JSCreate (index .Results 0)}}($result); {{- else}} @@ -79,9 +79,7 @@ import * as $models from "./{{js $models}}"; {{- end}}{{end}} return $result; {{- end}} - }) as any; - $typingPromise.cancel = $resultPromise.cancel.bind($resultPromise); - return $typingPromise; + }); {{- end}} } {{end}} diff --git a/v3/internal/generator/testdata/tsconfig.json b/v3/internal/generator/testdata/tsconfig.json index 8bfb46227..aa4939e6a 100644 --- a/v3/internal/generator/testdata/tsconfig.json +++ b/v3/internal/generator/testdata/tsconfig.json @@ -1,28 +1,35 @@ { - "compilerOptions": { - "allowJs": true, - "noEmit": true, - "skipLibCheck": true, + "include": ["output/**/*.js", "output/**/*.ts"], + "exclude": ["output/**/*.got.?s"], + "references": [ + { "path": "../../runtime/desktop/@wailsio/runtime" } + ], + "compilerOptions": { + "allowJs": true, - "target": "ES6", - "lib": ["ES6", "DOM"], + "noEmit": true, + "skipLibCheck": true, - "module": "ES6", - "moduleResolution": "Node", - "isolatedModules": true, - "esModuleInterop": true, + "target": "ES2015", + "module": "ES2015", + "moduleResolution": "bundler", + "isolatedModules": true, + "verbatimModuleSyntax": true, - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": false, - "noImplicitAny": false, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, + "lib": [ + "DOM", + "ESNext" + ], - "paths": { - "/wails/runtime.js": ["../../runtime/desktop/@wailsio/runtime/types/index.d.ts"] - } - }, - "include": ["output/**/*"], - "exclude": ["output/**/*.got.?s"] + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": false, + "noImplicitAny": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + + "paths": { + "/wails/runtime.js": ["../../runtime/desktop/@wailsio/runtime/src/index.ts"] + } + } }