TypeScript Checker Symbol Of "this" - typescript-compiler-api

I have this ts.Program/ts.SourceFile:
class MyClass {
foo() {
// #1
}
}
Is there a way to obtain the symbol/type of the local this value at position #1?
Unfortunately, this is not listed by checker.getSymbolsInScope.
Ideally I would get the type of MyClass, so I could explore its members.
The solution should also work for these cases:
function foo(this: MyClass) {
// #2
}
const obj = {
bar() {
// #3
}
};
Thank you!
edit: This is the feature I needed this for:

There is an internal TypeChecker#tryGetThisTypeAt(nodeIn: ts.Node, includeGlobalThis = true): ts.Type method that will return this information. If you're ok with using internal API, then you can do:
const type = (checker as any).tryGetThisTypeAt(nodeName) as ts.Type;
To get the node's name, you'll need to traverse the tree to find the method or function declaration that is contained within the position, then the .name property will contain the node that you can provide to tryGetThisTypeAt.

Related

How do I get the value of a property with reflection

I want to use the values of all properties that have some annotation. For the most part my code works, I get all the properties and only take those that have that annotation.
private inline fun <reified A : Annotation> (target: Any) {
target::class.memberProperties
.filter { it.annotations.any { annotation -> annotation is A } }
.forEach {
// How do I get the value here?
}
}
I wanted to use it.get(...) but get expects a Nothing as parameter. Same goes for getter. Calling it.call(target) does work but it looks wrong since there is an actuall get which I don't know how to invoke.
So what is the correct way of getting the properties value?
The problem boils down to the fact that T::class gives you a KClass<T>, whereas t::class gives you a KClass<out T>. Consider the following:
class Foo {
val foo = 2
val bar = 3
}
fun f() {
val any: Any = Foo()
any::class.memberProperties.forEach {
println(it.get(2)) // Oops
}
}
This would essentially attempt to access 2.foo and 2.bar, but it's not allowed because get errs on the side of caution instead of allowing a parameter of type Any. It appears doing t.javaClass.kotlin will produce a KClass<T>, however. Misusing it as above causes an IllegalArgumentException.
You can give the compiler some more help by providing a compile-time guarantee that the KClass will be for the type and nothing else:
private inline fun <reified A : Annotation, reified T : Any> foo(target: T) {
T::class.memberProperties
.filter { it.annotations.any { annotation -> annotation is A } }
.forEach {
println(it.get(target))
}
}
Unfortunately, I don't know if it's possible to specify A while deducing T from target. I haven't found a way past calling it like foo<Attr, Bar>(bar).
Alternatively, you can go through javaClass, though I'd wager it's less portable:
private inline fun <reified A : Annotation> foo(target: Any) {
target.javaClass.kotlin.memberProperties
.filter { it.annotations.any { annotation -> annotation is A } }
.forEach {
println(it.get(target))
}
}
We know this won't run into the above problem because we pass the same object in both cases. This also looks nicer on the caller's side, which might be worth the portability hit, assuming there is one.

If I just want to determine a value is present, which Swift data structure should I use?

I'm looking at a bunch of names, and I want to record all the names. My plan was to iterate over the array of names, and use a dictionary to keep track of each name, so I could just look up the name in the dictionary in O(1) time to see if it existed.
What would be the best data structure for this available in Swift? (I'd love to learn the name of the generic data structure that would be best for this, even if it's not in Swift.)
A Dictionary object would do fine, but it requires a value for the key, when I really only need the key.
You're looking for a Set (a collection of unordered unique objects - some implementations are ordered, though).
Swift and ObjectiveC have NSSet, wouldn't this work for you?
Swift does not provide a set type. You can refer to this blog post for how to define a Set.
Code reproduced here for quick reference:
struct Set<T: Hashable> {
typealias Element = T
private var contents: [Element: Bool]
init() {
self.contents = [Element: Bool]()
}
/// The number of elements in the Set.
var count: Int { return contents.count }
/// Returns `true` if the Set is empty.
var isEmpty: Bool { return contents.isEmpty }
/// The elements of the Set as an array.
var elements: [Element] { return Array(self.contents.keys) }
/// Returns `true` if the Set contains `element`.
func contains(element: Element) -> Bool {
return contents[element] ?? false
}
/// Add `newElements` to the Set.
mutating func add(newElements: Element...) {
newElements.map { self.contents[$0] = true }
}
/// Remove `element` from the Set.
mutating func remove(element: Element) -> Element? {
return contents.removeValueForKey(element) != nil ? element : nil
}
}
Otherwise, you can just use Dictionary and use the name as both key and value.

How to change the variable name by reflection?

I have a variable like this:
People model=Mock()//created by spock' mock
How to change the variable name "model" to "model_0" by reflection?
I doubt there is any way to do that with reflection. I'm with #tim_yates in this one.
I'm no bytecode/compiler expert, but i do believe variable's names turn into symbols upon compilation, so they are not changeable at all. The following Java class:
public class Var {
void a() {
int myVar = 1;
myVar += 1;
}
}
Upon compilation and decompilation (using jd-gui), the code turns into:
public class Var
{
void a()
{
int i = 1;
i++;
}
}
The variable name changed.
On Groovy, you can go for ASTs, which will give you full power over the generated tree. The following class:
class Asts {
def wat() {
Integer myVar = 90
}
}
Will generate the following AST:
Now you can write your own AST transformation to make the changes. Doesn't seem worth to me, though, a collection or map should suffice.

Passing values between functions

Hi All is there any way to locally define a variable in a function and then pass it to the oher function. I mean to say is it possible the pass a local value from one function to other function.
Somebody Please suggest me the solution.
Thanks in advance
Or it's that simple or you meant something else:
private function function1():void
{
var localVariable:String = "this is local variable of function1()";
function2(localVariable);
}
private function function2(string:String):void
{
trace(string);
}
function1();
or use global variable as temporary storage:
private var globalVariable:String = "";
private function function1():void
{
var localVariable:String = "this is local variable of function1()";
globalVariable = localVariable;
}
private function function2():void
{
trace(globalVariable);
}
function1();
function2();
zdmytriv is right.
Although, you can also make default variables, like so:
(Modifying zdmytriv's code)
private function function1():void
{
var localVariable:String = "this is local variable of function1()";
function2(localVariable);
function2(); //You don't have to enter a default argument
}
private function function2(string:String = "something else"):void
{
trace(string);
}
This would trace:
this is local variable of function1()
something else
A little off topic, but good to know.
Primitives in Flex are passed by value, where complex objects are passed by reference. You can use this to pass objects around without scoping a variable outside the functions themselves. For instance:
private function function1():void {
{
var localVar:Object = {value:"test"};
trace(localVar.value);
function2(localVar);
trace(localVar.value);
}
private function function2(obj:Object):void
{
obj.value = "new value";
}
This would trace:
test
new value
Which reflects the fact that function2 receives the parameter "obj" by reference, as a pointer to the original "localVar" object. When it sets the .value field, that change is reflected in function1.
I just thought I'd point that out.

Is it possible to define a generic type Vector in Actionsctipt 3?

Hi i need to make a VectorIterator, so i need to accept a Vector with any type. I am currently trying to define the type as * like so:
var collection:Vector.<*> = new Vector<*>()
But the compiler is complaining that the type "is not a compile time constant". i know a bug exists with the Vector class where the error reporting, reports the wrong type as missing, for example:
var collection:Vector.<Sprite> = new Vector.<Sprite>()
if Sprite was not imported, the compiler would complain that it cannot find the Vector class. I wonder if this is related?
So it looks like the answer is there is no way to implicitly cast a Vector of a type to valid super type. It must be performed explicitly with the global Vector.<> function.
So my actual problem was a mix of problems :)
It is correct to use Vector. as a generic reference to another Vector, but, it cannot be performed like this:
var spriteList:Vector.<Sprite> = new Vector.<Sprite>()
var genericList:Vector.<Object> = new Vector.<Object>()
genericList = spriteList // this will cause a type casting error
The assignment should be performed using the global Vector() function/cast like so:
var spriteList:Vector.<Sprite> = new Vector.<Sprite>()
var genericList:Vector.<Object> = new Vector.<Object>()
genericList = Vector.<Object>(spriteList)
It was a simple case of me not reading the documentation.
Below is some test code, I would expect the Vector. to cast implicitly to Vector.<*>.
public class VectorTest extends Sprite
{
public function VectorTest()
{
// works, due to <*> being strictly the same type as the collection in VectorContainer
var collection:Vector.<*> = new Vector.<String>()
// compiler complains about implicit conversion of <String> to <*>
var collection:Vector.<String> = new Vector.<String>()
collection.push("One")
collection.push("Two")
collection.push("Three")
for each (var eachNumber:String in collection)
{
trace("eachNumber: " + eachNumber)
}
var vectorContainer:VectorContainer = new VectorContainer(collection)
while(vectorContainer.hasNext())
{
trace(vectorContainer.next)
}
}
}
public class VectorContainer
{
private var _collection:Vector.<*>
private var _index:int = 0
public function VectorContainer(collection:Vector.<*>)
{
_collection = collection
}
public function hasNext():Boolean
{
return _index < _collection.length
}
public function get next():*
{
return _collection[_index++]
}
}
[Bindable]
public var selectedItems:Vector.<Category>;
public function selectionChange(items:Vector.<Object>):void
{
selectedItems = Vector.<Category>(items);
}
I believe you can refer to an untyped Vector by just calling it Vector (no .<>)
With Apache Flex 4.11.0, you can already do what you want. It might have been there since 4.9.0, but I have not tried that before.
var collection:Vector.<Object> = new Vector.<Object>()
maybe?
But i'm just speculating, haven't tried it.
var collection:Vector.<Object> = new Vector.<Object>()
but only on targeting flash player 10 cs4

Resources