Is casting to "keyof T" suppose to work or result in a compile error? - visual-studio

Consider the following TypeScript example:
interface MyInterface{
Prop1: string;
Prop2: number;
Prop3: string;
}
const myVar = "Prop4" as keyof MyInterface;
Running this code in Visual Studio 2017, Visual Studio Code and in Playground successfully compiles (TypeScript 2.9.2); the string value is not type checked against MyInterface but both VS and VSC show the 3 properties of MyInterface as IntelliSense suggestions:
const myVar: keyof MyInterface = "Prop4"; obviously works as intended and throws an error but the first example neither throws an error, nor ensures type safety.
Is this statement legal? If so, how is it suppose to behave? If not, why does it compile?

You are using a type assertion, a type assertion by definition overrides what the compiler knows to be true with what you, as the developer decide is true. If you tell the compiler the string it knows not to be an key of MyInterface is a key of MyInterface it will accept this as it is designed to do (although it will prevent you from asserting between unrelated types, eg this will be an error: let d = true as keyof MyInterface;).
If you want a variable to be typed as the key of an interface but still check that the value assigned to it is valid you can specify the type explicitly as you have.
You could also use a helper function:
interface MyInterface {
Prop1: string;
Prop2: number;
Prop3: string;
}
function keyOf<T>(key: keyof T) {
return key;
}
const myVar = keyOf<MyInterface>("Prop4"); //Argument of type '"Prop4"' is not assignable to parameter of type '"Prop1" | "Prop2" | "Prop3"'.
const myVar2 = keyOf<MyInterface>("Prop3");
Playground link

Related

Extends a Error struct, but encounter Type '*MyError' has both field and method named 'Error'

I come from java.
And I am using a framework that already define an Error in errs package, I want to extend it so that I can add more fields to it. So I try using inheritance of go.
// Error to inherit from errs.Error
type MyError struct {
errs.Error
ErrDetail string //more message to my error
st []uintptr
}
// override Error() so that the message can be more specific
func (e *MyError) Error() string {
if e == nil {
return ErrorCodeSuccess.ErrDetail
}
return fmt.Sprintf("Code:%d, ErrDetail:%s, Msg:%s", e.GetCode(), e.GetErrDetail(), e.GetMsg())
}
This is very straightforward for a java programmer. But I get
Type '*MyError' has both field and method named 'Error'.
This is very frustrating since the method Error is define in built-in package, and the name Error is define in my framework, is there any workaround to solve this problem?
You can use a type alias:
type SDKErr = errs.Error
// Error to inherit from errs.Error
type MyError struct {
SDKErr
ErrDetail string //more message to my error
st []uintptr
}
func (e *MyError) Error() string {
// ...
}
Now the name of the embedded field is SDKErr, but it won't conflict with the method name, and it can be used wherever errs.Error is expected without the need to convert.
Playground: https://go.dev/play/p/XSWi5hzHGPh
Of course you could also use a named field, instead of an alias:
type MyError struct {
SDKErr errs.Error
ErrDetail string //more message to my error
st []uintptr
}
And then call the methods of errs.Error simply like e.SDKErr.GetCode(). However if MyError is meant, for example, to be serialized to JSON, the fields of errs.Error would appear as a nested object, whereas with the type alias they would be "flattened".
Basically if errs.Error were defined as:
type Error struct {
Code int
}
With the type alias and embedded field, JSON would look like:
{"Code":0,"ErrDetail":""}
vs named field:
{"SDKErr":{"Code":0},"ErrDetail":""}

golang initializing struct with embedded template: too few values in struct initializer

I'm trying to initialize a golang struct with an embedded template. Since templates have no fields, I would expect that assigning the correct number of variables to a constructor would work, but instead the compiler complains that
main.go:17:19: too few values in struct initializer
package main
import "fmt"
type TestTemplate interface {
Name() string
}
type TestBase struct {
name string
TestTemplate
}
func New(name string) *TestBase {
return &TestBase{name} // This fails
//return &TestBase{name: name} // This works
}
func (v *TestBase) Name() string {
return v.name
}
func main() {
fmt.Println(New("Hello"))
}
https://golang.org/ref/spec#Struct_types
An embedded field is still a field, the name of which is derived from its type, therefore TestBase has actually two fields and not one, namely name and TestTemplate.
This compiles just fine:
var t *TestBase
t.TestTemplate.Print()
So when initializing TestBase you either specify the field names or you initialize all fields.
These all compile:
_ = &TestBase{name, nil}
_ = &TestBase{name: name}
_ = &TestBase{name: name, TestTemplate: nil}
_ = &TestBase{TestTemplate: nil}
It looks like (as far as general concepts go) you're confusing interfaces with composition (which is kind of how Go approaches the whole inheritance question.
This post might be helpful for you: https://medium.com/#gianbiondi/interfaces-in-go-59c3dc9c2d98
So TestTemplate is an interface.
That means that the struct TestBase will implement the methods (whose signature is) defined in the interface.
You should implement Print for TestBase.
But in anycase the error you're getting is because when you initialize a struct with no field names specified, it expects all the field names to be entered, see
https://gobyexample.com/structs
So remove the composition TestTemplate from the struct (and implement the method defined in the interface instead), and it should work.
Also, FYI, the Stringer interface with String method is what fmt.Println expects to print an arbitrary struct (not a Print method) see: https://tour.golang.org/methods/17

Is there a way to nest an enum within a data class in Kotlin?

Is there a way to nest an enum within a data class in Kotlin?
data class D(val a:Any) {
enum class E {F,G}
...
}
Or to declare it inline within a function?
fun foo() {
enum class E {F,G}
doSomething()
}
I can't find documentation on the rules for where enums are allowed to be declared.
Yes, you can nest the enum in a data class, but not in a function:
data class Outer(val a: InnerEnum) {
enum class InnerEnum { A, B }
}
fun foo() {
val o = Outer(Outer.InnerEnum.A)
println(o) // --> Outer(a=A)
}
There is no kotlin specification for the syntax at present. if you want to find the specification you can see JLS, because Kotlin is based on Java, so some specifications also appropriate in Kotlin.
A nested enum type is implicitly static. It is permitted for the declaration of a nested enum type to redundantly specify the static modifier.
This implies that it is impossible to declare an enum type in the body of an inner class (§8.1.3), because an inner class cannot have static members except for constant variables.
and, all local classes are inner classes.
So the enum class can be declared anywhere except the local function scope and inner classes.
If you don't sure where can define a type you can try to prompt the scope in turn: local > class > top, then the kotlin compiler will give you the correct compiler error message to you. for example:
IF you define a const val in the local function, the compiler report the error as below:
fun local() {
const val foo="bar"
// ^--- the modifier `const` is not applicable to `local variable`
}
IF you define a const val in the common class/interface, the compiler will report the error as below:
interface Foo {
const val foo = "bar"
//^--- `const val` only allowed on top-level or objects.
}

TypeScript method type signature redundant

Maybe I'm seriously missing something, but I'm unable to get rid of a syntax problem with all my classes.
Here is an example :
class Foo {
bar: (x: string, y: number) => string = (xx: string, yy: number) : string => {
// do some stuff...
};
}
Since I'm enforcing type declarations using tslint, ALL my methods are written like this. It's horrible. Having to copy paste the arguments part, renaming the args names between the type declaration and the lambda declaration is soooo painfull.
So : is there a better way to combine type signature and lambda declaration without all the knee jerking ? I sincerely hope I have missed something and hope this is not "by design" ! :)
You need to configure TSLint to enforce types but ignore the type of the functions:
typedef enforces type definitions to exist. Rule options:
"call-signature" checks return type of functions
"parameter" checks type specifier of function parameters
"property-declaration" checks return types of interface properties
"variable-declaration" checks variable declarations
"member-variable-declaration" checks member variable declarations
You can use a file like this one to configure TSLint. And read this to learn more about how to configure it.
Edit:
If you're targeting ES5, you can also do something like this:
var bar = (x: string, y: number) : string => {
// do some stuff...
};
class Foo {
get bar () { return bar; }
}
var test = (new Foo).bar('hello', 3);
Or:
class Foo {
get bar () {
return (xx: string, yy: number): string => {
// do some stuff...
};
}
}
This way the method's context is preserved and it also exists on the prototype. There's also no need to copy the argument types, TSC will infer them.

Go - Interface containing slice wont compile

type MyType interface {
MyStringSlice []string
}
What is wrong with this?
It works well as a struct as in:
type MyType struct {
MyStringSlice []string
}
but compiles with the following error when set as interface:
syntax error: unexpected [, expecting (
An interface can only hold methods or other interfaces. Have a look at the Language Specification.

Resources