pkl-community / pkl-typescript

TypeScript language bindings for the Pkl programming language
https://www.npmjs.com/package/@pkl-community/pkl-typescript
Apache License 2.0
105 stars 1 forks source link

Overriding variables without type annotation create any #55

Closed gregory-essertel-ai closed 1 day ago

gregory-essertel-ai commented 1 day ago
abstract class Test1 {
   foo: String = "a"
}

class Test2 extends Test1 {
   foo = "b"
}

generate the following code:

// Ref: Pkl class `test.Test1`.
export interface Test1 {
  foo: string
}

// Ref: Pkl class `test.Test2`.
export interface Test2 extends Test1 {
  foo: pklTypescript.Any
}

could the child type be inferred from the parent?

jasongwartz commented 1 day ago

@gregory-essertel-ai Thanks for reporting and for the the example! Sadly this is a behaviour from Pkl itself, not from pkl-typescript. In Pkl, sub-classing a property completely overwrites the property from the parent class - so it looks like you're simply setting Test1.foo to default to "b", but your code actually creates an entirely new .foo in Test2 with no relationship to Test1.foo.

I wrote this extension to your code to demonstrate:

// run with:
// `pkl eval test.pkl -f json`

import "pkl:reflect"

abstract class Test1 {
   foo: String = "a"
}

class Test2 extends Test1 {
   foo = "b"
}

function typeName(c: Class, prop: String): String = 
  let (ref = reflect.Class(c).properties[prop].type)
  if (ref is reflect.DeclaredType) ref.referent.name
  else ref.getClass().simpleName

output {
  value = new Mapping<String, String> {
    ["Test1.foo"] = typeName(Test1, "foo")
    ["Test2.foo"] = typeName(Test2, "foo")
  }
}

Which prints:

{
  "Test1.foo": "String",
  "Test2.foo": "UnknownType"
}

So you can see that Test2.foo has not inherited the type annotation from its parent. If you want Test2.foo to be typed, you have to write it like:

abstract class Test1 {
   foo: String = "a"
}

class Test2 extends Test1 {
   foo: String = "b"
}

Which, annoyingly, doesn't guarantee that the type of Test2.foo matches the type of Test1.foo.

Feel free to join the community Discord if you want to ask more about it - you might be able to get some information on why it's implemented this way or find some better workarounds.

I don't currently see a GitHub Issue on pkl for this (from searching extends), so feel free to file: https://github.com/apple/pkl/issues

gregory-essertel-ai commented 1 day ago

I see, thanks for the response!