TypeScript Version: 2.2.2
This possible typings of props function from ramda for two arguments:
I wonder why if second object argument is not curried TS can not infer types in results:
declare function props<P1 extends string, P2 extends string, T1, T2>
(ps: [P1, P2], obj: {[K in P1]: T2} & {[K in P2]: T2}): [T1, T2];
props(['a', 'b'], {a: 1, b: '2'})[0] => // can not infer `number` type
props(['a', 'b'], {a: 1, b: '2'})[1] => // can not infer `string` type
And when curried it can:
// this is inferred
declare function props<P1 extends string, P2 extends string>
(ps: [P1, P2]): <T1, T2>(obj: {[K in P1]: T1} & {[K2 in P2]: T2})
=> [T1, T2];
props(['a', 'b'])({a: 1, b: '2'})[0] => // this can infer `number` type
props(['a', 'b'])({a: 1, b: '2'})[1] => // this can infer `string` type
Is TS going to make it work in future?
Type inference will also work with this declaration:
declare function props<P1 extends string, P2 extends string, O extends {[K in P1 | P2]: any}>
(ps: [P1, P2], obj: O): [O[P1], O[P2]];
In your first example, the mapped types for obj are additional inference sites for P1 and P2, which results in them being both inferred as 'a' | 'b'. In the curried case, P1 and P2 are fixed as 'a' and 'b', respectively, when the second function gets called, and therefore limit what each of the two intersected types matches.
@PyroVortex
Is it possible for this case to limit ps tuple size to 2? Or prohibit props that are not in obj
So it wouldn't allow:
// should be an error, as 'whatever' is not in {a: 1, b: '2'}`
props(['a', 'b', 'whatever'])({a: 1, b: '2'})[0]
I run into similar problem:
declare const a: { cb: (arg: number) => void }
declare function test1<T>(a: T, b: T): void;
test1(a, { cb(arg) { } }) // parameter 'arg' implicitly has an 'any' type
declare function test2<T>(a: T, b: () => T): void;
test2(a, () => ({ cb(arg) { } })) // parameter 'arg' implicitly has an 'any' type
declare function test3<T>(a: T): (b: T) => void // curried
test3(a)({ cb(arg) { } }) // (parameter) arg: number
declare function test4<T>(a: T): (b: () => T) => void // curried
test4(a)(() => ({ cb(arg) { } })) // (parameter) arg: number
Looks like there're some related issues: https://github.com/Microsoft/TypeScript/issues/23429, https://github.com/Microsoft/TypeScript/issues/22715 https://github.com/Microsoft/TypeScript/issues/25092
This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.
Most helpful comment
Type inference will also work with this declaration:
In your first example, the mapped types for
objare additional inference sites forP1andP2, which results in them being both inferred as'a' | 'b'. In the curried case,P1andP2are fixed as'a'and'b', respectively, when the second function gets called, and therefore limit what each of the two intersected types matches.