<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨 Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Even if you think you've found a *bug*, please read the FAQ first, especially the Common "Bugs" That Aren't Bugs section! Please help us by doing the following steps before logging an issue: * Search: https://github.com/Microsoft/TypeScript/search?type=Issues * Read the FAQ: https://github.com/Microsoft/TypeScript/wiki/FAQ Please fill in the *entire* template below. --> <!-- Please try to reproduce the issue with `typescript@next`. It may have already been fixed. --> **TypeScript Version:** 2.8.3 and 2.9.1 (I think. The actual version in playground) **Code** The next code works as expected. ```ts interface I { property: number; method1(): void; method2(a: string): number; } declare const ob: I; declare function foo<T, K extends keyof T>(ob: T, key: K): T[K]; const f1 = foo(ob, 'property'); // number const f2 = foo(ob, 'method1'); // () => void const f3 = foo(ob, 'method2'); // (a: string) => number // f1(); OK, not a function f2(); f3('a string'); ``` But I want to restrict the `key` parameter in `foo` to just functions. Since #21316, and as an example on that PR, we can use something like `FunctionPropertyNames`. ```ts type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; declare function bar<T, K extends FunctionPropertyNames<T>>(ob: T, key: K): T[K]; // const f4 = bar(ob, 'property'); OK, 'property' is not allowed const f5 = bar(ob, 'method1'); // () => void | (a: string) => number const f6 = bar(ob, 'method2'); // () => void | (a: string) => number // ERROR! Both are of type '() => void | (a: string) => number' f5(); f6('a string'); // Type assertion const f7 = bar(ob, 'method1' as 'method1'); // () => void const f8 = bar(ob, 'method2' as 'method2'); // (a: string) => number // OK again f7(); f8('a string'); ``` **Expected behavior:** `f5` and `f6` inferred to `() => void` and `(a: string) => number`, respectively, without need a type assertion (pretty much as the first snippet). **Actual behavior:** `f5` and `f6` are both inferred to `() => void | (a: string) => number`, which is very odd since I'm passing a literal string. **Playground link** [Playground link](https://www.typescriptlang.org/play/index.html#src=interface%20I%20%7B%0D%0A%20%20%20%20property%3A%20number%3B%0D%0A%20%20%20%20method1()%3A%20void%3B%0D%0A%20%20%20%20method2(a%3A%20string)%3A%20number%3B%20%0D%0A%7D%0D%0A%0D%0Adeclare%20const%20ob%3A%20I%3B%0D%0A%0D%0A%0D%0Adeclare%20function%20foo%3CT%2C%20K%20extends%20keyof%20T%3E(ob%3A%20T%2C%20key%3A%20K)%3A%20T%5BK%5D%3B%0D%0A%0D%0Aconst%20f1%20%3D%20foo(ob%2C%20'property')%3B%20%2F%2F%20number%0D%0Aconst%20f2%20%3D%20foo(ob%2C%20'method1')%3B%20%2F%2F%20()%20%3D%3E%20void%0D%0Aconst%20f3%20%3D%20foo(ob%2C%20'method2')%3B%20%2F%2F%20(a%3A%20string)%20%3D%3E%20number%0D%0A%0D%0A%2F%2F%20f1()%3B%20OK%2C%20not%20a%20function%0D%0Af2()%3B%0D%0Af3('a%20string')%3B%0D%0A%0D%0Atype%20FunctionPropertyNames%3CT%3E%20%3D%20%7B%20%5BK%20in%20keyof%20T%5D%3A%20T%5BK%5D%20extends%20Function%20%3F%20K%20%3A%20never%20%7D%5Bkeyof%20T%5D%3B%0D%0Adeclare%20function%20bar%3CT%2C%20K%20extends%20FunctionPropertyNames%3CT%3E%3E(ob%3A%20T%2C%20key%3A%20K)%3A%20T%5BK%5D%3B%0D%0A%0D%0A%2F%2F%20const%20f4%20%3D%20bar(ob%2C%20'property')%3B%20OK%2C%20'property'%20is%20not%20allowed%20%20%0D%0Aconst%20f5%20%3D%20bar(ob%2C%20'method1')%3B%20%2F%2F%20()%20%3D%3E%20void%20%7C%20(a%3A%20string)%20%3D%3E%20number%0D%0Aconst%20f6%20%3D%20bar(ob%2C%20'method2')%3B%20%2F%2F%20()%20%3D%3E%20void%20%7C%20(a%3A%20string)%20%3D%3E%20number%0D%0A%0D%0A%0D%0A%2F%2F%20ERROR!%20Both%20are%20of%20type%20'()%20%3D%3E%20void%20%7C%20(a%3A%20string)%20%3D%3E%20number'%0D%0Af5()%3B%20%2F%2F%20should%20be%20inferred%20as%20'()%20%3D%3E%20void'%0D%0Af6('a%20string')%3B%20%2F%2F%20should%20be%20inferred%20as%20'(a%3A%20string)%20%3D%3E%20number'%0D%0A%0D%0A%0D%0A%2F%2F%20Type%20assertion%0D%0Aconst%20f7%20%3D%20bar(ob%2C%20'method1'%20as%20'method1')%3B%20%2F%2F%20()%20%3D%3E%20void%0D%0Aconst%20f8%20%3D%20bar(ob%2C%20'method2'%20as%20'method2')%3B%20%2F%2F%20(a%3A%20string)%20%3D%3E%20number%0D%0A%0D%0A%2F%2F%20OK%20again%0D%0Af7()%3B%0D%0Af8('a%20string')%3B%0D%0A) **Related Issues:** <!-- Did you find other bugs that looked similar? --> Maybe #24080 (but that seems related to the `keyof T` ~ `string | number | symbol` issue and my example fails with TS 2.8)