Closed as not planned
Closed as not planned

Description
π Search Terms
generics, type parameters, dependent properties
π Version & Regression Information
None of the versions I have tried work as expected.
β― Playground Link
π» Code
namespace round_one {
// let's start with declaring a function that:
// - accepts a numeric `primaryProperty`
// - accepts `dependentProperty` which should be identical to `primaryProperty`
// - accepts optional `dependentFunctionProperty` which is a function with a parameter based on `primaryProperty`
declare function define<const obj extends {
readonly primaryProperty: number
dependentProperty: obj['primaryProperty']
dependentFunctionProperty?: (primary: obj['primaryProperty']) => void
}>(obj: obj): obj
// so far everything works as expected
define( {
primaryProperty: 11,
dependentProperty: 11, // no errors
} )
define( {
primaryProperty: 11,
dependentProperty: 13, // an error
} )
define( {
primaryProperty: 11,
dependentProperty: 11,
dependentFunctionProperty: () => {}, // no errors if there is no parameter
} )
// but when we add a parameter to `dependentFunctionProperty`, it breaks because...
define( {
primaryProperty: 11,
dependentProperty: 11,
// Type '(primary: number) => void' is not assignable to type '(primary: unknown) => void'.
// though we didn't state which type we expect in the parameter! and why did `primary` become `unknown`?
dependentFunctionProperty: (primary) => {
primary
},
} )
}
namespace round_two {
// if we replace a function property with a method, things get even weirder.
declare function define<const obj extends {
readonly primaryProperty: number
dependentProperty: obj['primaryProperty']
dependentMethod(primary: obj['primaryProperty']): void
}>(obj: obj): obj
define( {
primaryProperty: 11,
dependentProperty: 11,
dependentMethod(primary) {
// `primary` is not inferred as `unknown` now, but still is not `11`: it's a `number`
primary
},
} )
// but we can manually annotate `primary` without any problems
// which would be impossible for "normal" function signatures expecting `number`
define( {
primaryProperty: 11,
dependentProperty: 11,
dependentMethod(primary: 11) { // no errors
primary
},
} )
// annotating `primary` with something different than 11 results in an error as well
define( {
primaryProperty: 11,
dependentProperty: 11,
dependentMethod(primary: 12) { // an error
primary
},
} )
}
namespace round_three {
// now we get to the weirdest part of the problem.
// accidentally i've discovered that simply repeating
// the declaration of `define` makes typescript behave almost correctly
declare function define<const obj extends {
readonly primaryProperty: number
dependentProperty: obj['primaryProperty']
dependentFunctionProperty?: (primary: obj['primaryProperty']) => void
}>(obj: obj): obj
declare function define<const obj extends {
readonly primaryProperty: number
dependentProperty: obj['primaryProperty']
dependentFunctionProperty?: (primary: obj['primaryProperty']) => void
}>(obj: obj): obj
define( {
primaryProperty: 11,
dependentProperty: 11,
// no errors here, but hovering over `primary` shows `number` as if we were declaring `dependentFunctionProperty` as a method
dependentFunctionProperty: (primary) => {
primary
},
} )
// annotating `primary` works like in `dependentMethod` as well
define( {
primaryProperty: 11,
dependentProperty: 11,
dependentFunctionProperty: (primary: 11) => { // no errors
primary
},
} )
define( {
primaryProperty: 11,
dependentProperty: 11,
dependentFunctionProperty: (primary: 12) => { // an error
primary
},
} )
}
π Actual behavior
I'm not sure where to begin. Properties of a type parameter that reference other properties of the same type parameter seem to be completely untested in TypeScript.
In the example above, I have referenced a generic's property from other properties in three ways:
- from a function property
- from a method
- from a function property, but declaration of the function is duplicated!
All of them are buggy, but in different ways.
π Expected behavior
Speaking honestly, I was expecting from such dependent properties to not work at all, failing with some kind of circular constraint error, but now I believe they could become usable some day.
Additional information about the issue
No response