TypeScript lets you define an interface which is both callable and has properties:
interface FnWithProps {
(x: number): number;
a: string;
b: string;
}
Here's one way to create values assignable to this interface:
function double(x: number) {
return x * x;
}
double.a = 'Hello';
double.b = 'Goodbye';
let f: FnWithProps = double; // ok
If double.a
or double.b
are not set, this triggers an error.
Is it possible to construct such a value directly, without going through an intermediate or using a type assertion?
This isn't valid TypeScript and triggers all sorts of errors:
let g: FnWithProps = {
(x: number) => x,
a: 'Hello',
b: 'Goodbye',
};
I think the intermediate solution is probably the best one as it works well for overloads too, but you can also use Object.assign
to get a similar effect :
let f: FnWithProps = Object.assign(function double(x: number) {
return x * x;
},{
a : 'Hello',
b : 'Goodbye'
});
Although this does mean we don't get inference for the function params or the properties.
If this is a common scenario for you, we can build a utility function to get inference for everything:
interface FnWithProps {
(x: number): number;
a: string;
b: string;
}
function functionWithProps<T extends (...a: any[]) => any>(fn: (...a: Parameters<T>) => ReturnType<T>, props: Pick<T, keyof T>){
return Object.assign(fn, props);
}
let f = functionWithProps<FnWithProps>(function double(x) { // annotation not necesary
return x * x;
},{
a : 'Hello', // helpful intelisense here
b : 'Goodbye'
});