@@ -646,7 +646,7 @@ func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, err
646
646
// Just append these as fields. We should fix this later.
647
647
state .Fields = append (state .Fields , tsType .AboveTypeLine )
648
648
}
649
- state .Fields = append (state .Fields , fmt .Sprintf ("%sreadonly %s%s: %s" , indent , jsonName , optional , valueType ))
649
+ state .Fields = append (state .Fields , fmt .Sprintf ("%sreadonly %s%s: %s; " , indent , jsonName , optional , valueType ))
650
650
}
651
651
652
652
// This is implemented to ensure the correct order of generics on the
@@ -759,12 +759,8 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) {
759
759
// }
760
760
// }
761
761
return TypescriptType {
762
- ValueType : "any" ,
763
- AboveTypeLine : fmt .Sprintf ("%s\n %s" ,
764
- indentedComment ("Embedded anonymous struct, please fix by naming it" ),
765
- // Linter needs to be disabled here, or else it will complain about the "any" type.
766
- indentedComment ("eslint-disable-next-line @typescript-eslint/no-explicit-any -- Anonymously embedded struct" ),
767
- ),
762
+ AboveTypeLine : indentedComment ("Embedded anonymous struct, please fix by naming it" ),
763
+ ValueType : "unknown" ,
768
764
}, nil
769
765
case * types.Map :
770
766
// map[string][string] -> Record<string, string>
@@ -815,16 +811,11 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) {
815
811
}
816
812
genValue := ""
817
813
818
- // Always wrap in parentheses for proper scoped types.
819
- // Running prettier on this output will remove redundant parenthesis,
820
- // so this makes our decision-making easier.
821
- // The example that breaks without this is:
822
- // readonly readonly string[][]
823
814
if underlying .GenericValue != "" {
824
- genValue = "(readonly " + underlying .GenericValue + "[]) "
815
+ genValue = "Readonly<Array< " + underlying .GenericValue + ">> "
825
816
}
826
817
return TypescriptType {
827
- ValueType : "(readonly " + underlying .ValueType + "[]) " ,
818
+ ValueType : "Readonly<Array< " + underlying .ValueType + ">> " ,
828
819
GenericValue : genValue ,
829
820
AboveTypeLine : underlying .AboveTypeLine ,
830
821
GenericTypes : underlying .GenericTypes ,
@@ -858,6 +849,8 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) {
858
849
return TypescriptType {ValueType : "boolean" }, nil
859
850
case "github.com/coder/serpent.Duration" :
860
851
return TypescriptType {ValueType : "number" }, nil
852
+ case "net/netip.Addr" :
853
+ return TypescriptType {ValueType : "string" }, nil
861
854
case "net/url.URL" :
862
855
return TypescriptType {ValueType : "string" }, nil
863
856
case "time.Time" :
@@ -889,6 +882,14 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) {
889
882
return TypescriptType {ValueType : "HealthSection" }, nil
890
883
case "github.com/coder/coder/v2/codersdk.ProvisionerDaemon" :
891
884
return TypescriptType {ValueType : "ProvisionerDaemon" }, nil
885
+
886
+ // Some very unfortunate `any` types that leaked into the frontend.
887
+ case "tailscale.com/tailcfg.DERPNode" ,
888
+ "tailscale.com/derp.ServerInfoMessage" ,
889
+ "tailscale.com/tailcfg.DERPRegion" ,
890
+ "tailscale.com/net/netcheck.Report" ,
891
+ "github.com/spf13/pflag.Value" :
892
+ return TypescriptType {AboveTypeLine : indentedComment ("TODO: narrow this type" ), ValueType : "any" }, nil
892
893
}
893
894
894
895
// Some hard codes are a bit trickier.
@@ -965,15 +966,15 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) {
965
966
966
967
// If it's a struct, just use the name of the struct type
967
968
if _ , ok := n .Underlying ().(* types.Struct ); ok {
968
- // External structs cannot be introspected, as we only parse the codersdk package.
969
- // You can handle your type manually in the switch list above, otherwise "any" will be used.
970
- // An easy way to fix this is to pull your external type into `codersdk` package, then it will
971
- // be known by the generator.
972
- return TypescriptType { ValueType : "any" , AboveTypeLine : fmt . Sprintf ( "%s \n %s" ,
973
- indentedComment ( fmt . Sprintf ( "Named type %q unknown, using \" any \" " , n . String ())),
974
- // Linter needs to be disabled here, or else it will complain about the "any" type.
975
- indentedComment ( "eslint-disable-next-line @typescript-eslint/no-explicit-any -- External type" ) ,
976
- ) }, nil
969
+ // External structs cannot be introspected, as we only parse the codersdk
970
+ // package. You can handle your type manually in the switch list above,
971
+ // otherwise `unknown` will be used. An easy way to fix this is to pull
972
+ // your external type into codersdk, then it will be known by the
973
+ // generator.
974
+ return TypescriptType {
975
+ AboveTypeLine : indentedComment ( fmt . Sprintf ( "external type %q, using \" unknown \" " , n . String ())),
976
+ ValueType : "unknown" ,
977
+ }, nil
977
978
}
978
979
979
980
// Defer to the underlying type.
@@ -1002,20 +1003,16 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) {
1002
1003
// This field is 'interface{}'. We can't infer any type from 'interface{}'
1003
1004
// so just use "any" as the type.
1004
1005
return TypescriptType {
1005
- ValueType : "any" ,
1006
- AboveTypeLine : fmt .Sprintf ("%s\n %s" ,
1007
- indentedComment ("Empty interface{} type, cannot resolve the type." ),
1008
- // Linter needs to be disabled here, or else it will complain about the "any" type.
1009
- indentedComment ("eslint-disable-next-line @typescript-eslint/no-explicit-any -- interface{}" ),
1010
- ),
1006
+ AboveTypeLine : indentedComment ("empty interface{} type, falling back to unknown" ),
1007
+ ValueType : "unknown" ,
1011
1008
}, nil
1012
1009
}
1013
1010
1014
1011
// Interfaces are difficult to determine the JSON type, so just return
1015
- // an 'any '.
1012
+ // an 'unknown '.
1016
1013
return TypescriptType {
1017
- ValueType : "any" ,
1018
- AboveTypeLine : indentedComment ( "eslint-disable-next-line @typescript-eslint/no-explicit-any -- Golang interface, unable to resolve type." ) ,
1014
+ AboveTypeLine : indentedComment ( "interface type, falling back to unknown" ) ,
1015
+ ValueType : "unknown" ,
1019
1016
Optional : false ,
1020
1017
}, nil
1021
1018
case * types.TypeParam :
@@ -1040,13 +1037,13 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) {
1040
1037
// If we don't have the type constraint defined somewhere in the package,
1041
1038
// then we have to resort to using any.
1042
1039
return TypescriptType {
1040
+ AboveTypeLine : fmt .Sprintf ("// %q is an external type, falling back to unknown" , name ),
1043
1041
GenericTypes : map [string ]string {
1044
- ty .Obj ().Name (): "any " ,
1042
+ ty .Obj ().Name (): "unknown " ,
1045
1043
},
1046
- GenericValue : ty .Obj ().Name (),
1047
- ValueType : "any" ,
1048
- AboveTypeLine : fmt .Sprintf ("// %q is an external type, so we use any" , name ),
1049
- Optional : false ,
1044
+ GenericValue : ty .Obj ().Name (),
1045
+ ValueType : "unknown" ,
1046
+ Optional : false ,
1050
1047
}, nil
1051
1048
}
1052
1049
// Include the builtin for this type to reference
@@ -1097,7 +1094,7 @@ func (Generator) isBuiltIn(name string) (bool, string) {
1097
1094
case "comparable" :
1098
1095
// To be complete, we include "any". Kinda sucks :(
1099
1096
return true , "export type comparable = boolean | number | string | any"
1100
- case "any" :
1097
+ case "any" , "unknown" :
1101
1098
// This is supported in typescript, we don't need to write anything
1102
1099
return true , ""
1103
1100
default :
0 commit comments