a typescript code confusing me - typescript2.0

There is a question confusing me so much。
The tutorial on the site(http://www.typescriptlang.org)introduces the grammar as follows:
https://i.stack.imgur.com/3t4ui.png
It means that {name:”Alice”} is the subtype of {name:”Alice”,location:”seattle”}( obviously,has excess property),but the typescript document tells us as follow:
"S is a subtype of a type T, and T is a supertype of S, if S has no excess properties with respect to T"

I believe what it is telling you is that the object y must be of the same type as the object x or at least a sub-type. x is part of y, but not the other way around. This is a more specific example of the differences using classes instead of objects,
class x {
constructor(public name: string){}
}
class y extends x {
constructor(public name: string, public location: string){
super(name);
}
}
let myX: x = y; // OK
let myY: y = x; // Error: "Type 'typeof x' is not assignable to type 'y'. Property 'location' is missing in type 'typeof x'. let myY: y"
// PLUG this code in the typescript playground to see it work, or not... :)

Related

Kotlin Type Mismatch "Nothing"

Consider the following code, which has been stripped back to illustrate only the problem with generics:
interface Node
interface GenericNode<T : GenericNode<T>> : Node {
val pointer: NodePtr<T>?
}
class NodePtr<T : Node>(private val value: T) {
fun isPointingTo(other: T): Boolean {
return value == other
}
}
class BasicNode : Node
class GenericNodeImpl(override val pointer: NodePtr<GenericNodeImpl>) : GenericNode<GenericNodeImpl>
Node may have many implementations. Here we have GenericNode<T : GenericNode<T>> which contains a pointer to another GenericNode<T : GenericNode<T>> (consider this sort of like a singly-linked list mechanism), and we have BasicNode.
Now consider the following which demonstrates the problem:
fun main(args: Array<String>) {
val a = GenericNodeImpl(null)
val b = GenericNodeImpl(NodePtr(a))
val c = GenericNodeImpl(NodePtr(b))
val d = BasicNode()
val list: List<Node> = listOf(a, b, c, d)
list.filterIsInstance<GenericNode<*>>().filter { it.pointer?.isPointingTo(a) ?: false }
}
I've declared List<Node> as it can contain any Node type, but then I want to filter any instances of type GenericNode<*>. I don't care about the specific implementation, or what T is in this case, it just has to be GenericNode<*>.
For each of those nodes, I want to know which ones are pointing to a, but isPointingTo(a) contains the following error:
Type mismatch.
Required: Nothing
Found: GenericNodeImpl
I'm assuming that the issue is caused by filtering GenericNode<*> where * is Unknown, but that is unavoidable. Is there an in or out missing somewhere?
Technically NodePtr could be contravariant in T (in T) because it only takes a T as input (to the isPointingTo() method).
As a consequence, GenericNode could also be in T, because T is only used for the pointer property which is now in T.
That being said, it doesn't solve your problem, because your problem is conceptual. You're filtering with GenericNode<*>, meaning you don't know what T is, and T could really be any subtype of GenericNode, including Nothing. This means that the following NothingGenericNode implementation could be a potential element in the list:
class NothingGenericNode(override val pointer: NodePtr<Nothing>?) : GenericNode<Nothing>
From there, you can see that pointer could be of type NodePtr<Nothing> and thus accept 0 possible values as argument of isPointingTo. The compiler protects you from that. It only allows you to pass arguments that would be valid for all possible subtypes of GenericNode. But since there is a subtype that accepts nothing at all, then your generic code cannot pass anything either.
One solution to this problem would be to be more lenient on what isPointingTo accepts. For instance it could maybe accept any subtype of Node instead of only the specific T:
fun isPointingTo(other: Node): Boolean

Generics; Type argument is not within its bounds

I've been experimenting with generics lately and found a good instance where I could use them, however, I've become stuck and my searches haven't resulted in a solution, or I've misunderstood. See below code sample:
open class X()
class Y : X()
class Z : X()
abstract class A<T : X> {
lateinit var one: T
fun setup(
one: T
) {
this.one = one
}
}
class B<T : Y> : A<T>()
class C {
fun initB() {
B<Y>() // Works as intended
B<Z>() // Type argument is not within its bounds
B<X>() // Type argument is not within its bounds
}
}
I would like to have a situation whereby accessing one from class B type of one is correctly inferred, so if I instantiate B with type Z then one will be inferred also as type Z. Unfortunately doing this how I thought was the correct way results in 'Type argument is not within its bounds'. Any help would be greatly appreciated.
B's type has to be a subtype of Y as you defined it B<T : Y>, but neither X nor Z is a subtype of Y. X is a supertype of Y, and Z has no vertical connection to Y at all.
Even if they were subtypes, you couldn't do what you were hoping to. Since your class has a T var, T has to be invariant for it to work. Invariant means you cannot implicitly up- and down-cast the type of an instance of the class.
Consider how it would break if it allowed you to:
val bY: B<Y> = B<Y>()
val bX: B<X> = bY // not allowed because of invariance
// If it were allowed:
bX.one = X()
val y: Y = bY.one // ClassCastException: cannot cast X to Y

Kotlin type inference for multiple possible types?

I have a function that takes parameter metadata of two possible types: Metadata1 or Metadata2. I'm trying to write a utility function that can be used for both since there is a ton of code reuse. Both of them have a list of DataPoint objects, each of which has name() method.
I thought in my code Kotlin would use type inference to know that dataPoints can only be one of two types that both have DataPoint.name() method, but I'm getting "unresolved reference: name". How can I make this function generic enough to apply to both Metadata1 and Metadata2?
var dataPoints: List<Any>
if (metadata is Metadata1) {
dataPoints = metadata.metadata1().dataPoints()
} else {
dataPoints = (metadata as Metadata2).metadata2().dataPoints()
}
if (data.size > 1) {
textView.test = dataPoints.fold("")
{ x, dataPoint ->
x + dataPoint.name() + " \n" // unresolved reference: name
}
}
This isn't unique to Kotlin, statically typed OOP languages work like this.
Your dataPoints is of type List<Any> and Any does not have a name() function. You're not showing a lot of code so I can't tell what kind of objects you have.
This is about run-time vs compile-time. The compiler can't predict what types you're going to put into your List<Any> at runtime and so the only functions you can call on its members are functions that belong to the Any class. Imagine if that list contained an object that didn't have a name() function. If the compiler allowed you to call name() then you'd have a run-time crash. This is why you get a compiler-time error when you try.
If you have two different types of objects that goes in the list, one way would be to make an interface that they both implement with shared methods in the interface. Which would look something like this:
interface Name {
fun name()
}
Change dataPoints to List<Name>, have your data classes implement that, and now dataPoint.name() compiles because the only objects allowed in the list are objects of type Name with a name() function.
var dataPoints: List<Name>
if (metadata is Metadata1) {
dataPoints = metadata.metadata1().dataPoints()
} else {
dataPoints = (metadata as Metadata2).metadata2().dataPoints()
}
if (data.size > 1) {
textView.test = dataPoints.fold("")
{ x, dataPoint ->
x + dataPoint.name() + " \n" // Compiles now
}
}
You have a similar problem with your Metadata1 and Metadata2 classes, they should probably implement an interface or extend a super class.

Go "polymorphism"

People are saying, Go is not an OO (Object Oriented) language; don't use OO terms on Go. OK, let me describe what I am able to do with OO --
With an OO language, I can make different animals say different things based on their classes:
cat.Say() // miao
sheep.Say() // bahh
cow.Say() // moo
The same is getting the Area() from Shapes.
However, this go demo code made me believe that it is impossible. Included below as Exhibit#1.
Then today, I found this go demo code, which makes it entirely possible. Included below as Exhibit#2.
So my question is, what's fundamentally different between the two, that makes the first one wrong and second one correct?
How to make the first one "works"?
Exhibit#1:
// Credits: hutch
// https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/0ij9yGHK_8EJ
////////////////////////////////////////////////////////////////////////////
/*
https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/tOO5ZXtwbhYJ
LRN:
Subtype polymorphism: Not applicable (Go doesn't have subtyping).
Although if you embed a struct A implementing interface X into a struct B,
struct B will implement interface X, and can be used instead of struct A in
places where struct A is expected. So, kind of yes.
Robert Johnstone:
interfaces behave similarly to virtual functions, but they are not identical. See the (following) example program by hutch.
*/
package main
import "fmt"
type A struct {
astring string
}
type B struct {
A
bstring string
}
type Funny interface {
strange()
str() string
}
func (this *A) strange() {
fmt.Printf("my string is %q\n", this.str())
}
func (this *A) str() string {
return this.astring
}
func (this *B) str() string {
return this.bstring
}
func main() {
b := new(B)
b.A.astring = "this is an A string"
b.bstring = "this is a B string"
b.strange()
// Output: my string is "this is an A string"
// Many people familiar with OO (and unfamiliar with Go) will be quite
// surprised at the output of that program.
}
Exhibit#2:
// Credits: https://play.golang.org/p/Zn7TjiFQik
////////////////////////////////////////////////////////////////////////////
/*
Problem (From Polymorphism-Subtype.go):
https://groups.google.com/d/msg/golang-nuts/N4MBApd09M8/tOO5ZXtwbhYJ
LRN: Subtype polymorphism: Not applicable (Go doesn't have subtyping).
Goal:
This is to demo that "polymorphism" is still doable in Go.
*/
package main
import (
"fmt"
)
type Shape interface {
Area() float32
}
type Point struct {
x float32
y float32
}
// Make sure the structs are different sizes so we're sure it'll work with
// all sorts of types
type Circle struct {
center Point
radius float32
}
func (c Circle) Area() float32 {
return 3.1415 * c.radius * c.radius
}
type Rectangle struct {
ul Point
lr Point
}
func (r Rectangle) Area() float32 {
xDiff := r.lr.x - r.ul.x
yDiff := r.ul.y - r.lr.y
return xDiff * yDiff
}
func main() {
mtDict := make(map[string]Shape)
// No problem storing different custom types in the multitype dict
mtDict["circ"] = Circle{Point{3.0, 3.0}, 2.0}
mtDict["rect"] = Rectangle{Point{2.0, 4.0}, Point{4.0, 2.0}}
for k, v := range mtDict {
fmt.Printf("[%v] [%0.2f]\n", k, v.Area())
}
}
/*
$ go run Polymorphism-Shape.go
[circ] [12.57]
[rect] [4.00]
*/
Your two exhibits are doing different things.
In the first one, B has A embedded in it, and B doesn't implement the strange() method itself, so when you call b.strange(), you get the implementation of strange() defined for A. The receiver (this) of the strange method is b.A, not b, so the value b.A.astring is printed. If you wanted strange to print bstring, you would have to define strange for B.
This points out one of the differences between Go and other OO languages: embedding A within B does not mean that B is a "subclass" of A, so an object of type B cannot be used where an object of type A is expected. However, since B inherits the fields and methods of A, any interface that's implemented by A is also implemented by B, and, unless those methods are defined specifically for B, they operate on the A within B, not B itself.
In the second exhibit, you have the Shape interface which is implemented by the types Circle and Rectangle. The element type of your map is Shape, so any type that implements that interface can be an element in the map. When working with a value of an interface type as you are doing in the loop, you can call any method defined in the interface on the value, and the definition corresponding to the actual type of the value will be called.
First of all I would like to discuss the "impossible" part.
import "fmt"
type Animal interface {
Say() string
}
type Cat struct {}
func (cat Cat) Say() string {
return "miao"
}
type Sheep struct {}
func (sheep Sheep) Say() string {
return "bahh"
}
type Cow struct {}
func (cow Cow) Say() string {
return "moo"
}
func main() {
cat := Cat{}
sheep := Sheep{}
cow := Cow{}
fmt.Println(cat.Say())
fmt.Println(sheep.Say())
fmt.Println(cow.Say())
}
This will work exactly as you would expect. So there is a polymorphism in terms of "different structs responding differently to same method".
The intention of Exhibit#1 demonstrates that what Go does is actually similar to Java castings before #Overrides.
Just add the following method to the first example and see how that will work:
func (this B) strange() {
fmt.Printf("my string is %q\n", this.str())
}

TypeScript dynamic property type on class

There is a way to declare the type of dynamic class property if it's accessed by [] operator, like on the following example:
class Foo {
[key: string]: number;
}
let a = new Foo();
let b = a['bar']; //Here, the compiler knows that b is a number
But is there a way to declare the same thing, without [] operator?
A way to write this:
let a = new Foo();
let b = a.someProperty;
And letting TypeScript knows that someProperty is of type number, because we say to it: All unknown properties on Foo are of type number.
I do not think its is possible. When you define class you define 'static' information about its properties and methods. If you specify indexer - it means just that - that the objects of the class will have indexer, not any properties. Thats what classes are for after all - to define structure of your business entities.
The only way I am aware of doing something similar to what you want is by using object literals. For example this will work:
let x: { PropA: number, [x: string]: number };
x = { PropA: 1, PropX: 2, PropY: 3, PropZ: 4 };
Hope this helps.