Alex Parloti
Alex Parloti

Reputation: 734

Restrict keyof 'Type' according to return type

How can I restrict the keys of an object to only those that return a certain type?

In the example below I want to ensure that the type of the property is a function, so that I can execute obj[key]().

interface IObj{
  p1:string,
  p2:number,
  p3:()=>void
}

const obj:IObj = {
  p1:'str',
  p2:5,
  p3:()=>void 0
}

function fun<TKey extends keyof IObj>(key: IObj[TKey] extends ()=>void? TKey:never){
  const p = obj[key]
  p(); // This expression is not callable.
       // Not all constituents of type 'string | number | (() => void)' are callable.
       // Type 'string' has no call signatures.(2349)
}

playground

Upvotes: 1

Views: 481

Answers (1)

brunnerh
brunnerh

Reputation: 184607

You can map the type to property name/never and then index into it, you have half of that already:

type FunctionKeys = {
    [K in keyof IObj]: IObj[K] extends () => void ? K : never
}[keyof IObj]; // <-

function fun(key: FunctionKeys) {
    const p = obj[key];
    p();
}

The indexing will perform a union over all the types of the properties and A | never is just A.

(Extracted the type because it's so long. Maybe there is a more elegant method.)

Upvotes: 2

Related Questions