TypeScript Version: nightly(2.1.0-dev.20161103)
Code
function prop<S, K extends keyof S>(name: K): (s: S) => any {
return s => s[name]
}
const getProp = prop('test')
const a = getProp({test: 123})
Expected behavior:
Code compiles, getProp is typed as (v: {test: {}}) => any
Actual behavior:
Argument of type "test" is not assignable to parameter of type 'never'
I don't know whether it is an intended behavior. As a comparison, flow seems to, well, cough partly, cough, support it.
https://flowtype.org/try/#0PQKgBAAgZgNg9gdzCYAoVUCuA7AxgFwEs5swAHAJzjIB4BlALjAHkAjAKwFMCAaMAaSYASfpwCeAZ3oA+aQApsAQwC2nJvwCUTORKZ0NYALzSwi7GLABvVGDAVO+TBVI69B42AkBtJaoC6qAC+6LgkEvhgAOYOAApUZEbk8XIA5Pic4SkaqKHY4aaJ0fhx1HKW6eFMAIwATADMgdlAA
The problem is that S isn't inferred as part of the call to the outermost arrow function, so you end up with {} as the type of S, and the empty union as the type of keyof S (because keyof {} is never). Thus, K has an effective constraint of never which "test" isn't compatible with.
As I pointed out with @ahejlsberg a few weeks ago, you really want a to _invert_ the contraint somehow:
function prop<K extends string>(name: K): <S extends { [K]: any }>(s: S) => S[K] {
return s => s[name];
}
Here, { [K]: any } means that for whatever K is, there is an object type with property names unioned within K.
I think I can mark this feature as a sub feature of https://github.com/Microsoft/TypeScript/issues/5683?
Works like a charm after #11929, fantastic!
function prop<K extends string>(k: K): <V>(v: {[k in K]: V} & {[k: string]: any}) => V {
return v => v[k]
}
var testProp = prop('test')
var num = testProp({test: 123, additional: 'additional'})
My brain hurts from reading that definition :(
Most helpful comment
My brain hurts from reading that definition :(