Assume I have the following type:
export type Foo<T> = (() => T)
Is it possible to remove the length
property from it while keep it callable ?
Also, using Omit
, Omit<(() => T), 'length'>
prevents it from being callable.
You can't really do this. All callables in TypeScript inherit from the Function
interface, which is defined in the TypeScript es5.d.ts library to have a numeric length
property. Anything you do that results in a callable type will have that length
property present.
The only way to change that would be to fork es5.d.ts locally and remove it, but this would probably break a lot of things and be difficult to maintain. Probably the "correct" approach would be to make a custom linter rule so that use of function length
warns you that it might be a mistake. Within TypeScript itself, though, you don't have too many options.
You can't widen a function to something without length
and still have it callable, but you can narrow a function to something whose length
is weird/unusable. The standard approach is to narrow to the never
type which is a universal subtype and therefore you can always narrow to it:
type Foo<T> = (() => T) & { length: never };
declare const f: Foo<string>;
f().length.toFixed(); // okay
f.length.toFixed(); // error
But that won't stop you from checking f.length
for truthiness, since even never
is allowed there. TypeScript complains about very little when it comes to truthiness checks; indeed the only thing I've found is when you check a function but don't call it. So we can do the crazy things of telling TypeScript that the length
property is both number
and some function:
type Foo<T> = (() => T) & { length(x: never): never };
declare const f: Foo<string>;
f().length.toFixed(); // okay
f.length.toFixed(); // error
if (f.length) { // error but for a crazy reason
console.log(1)
}
But that really is a vile lie; the error says that you meant to call f.length
and indeed you can sort of do that (although I made it harder by giving it a never
parameter):
f.length(null!) // no error, what?
So I'd say this isn't really the sort of thing TypeScript can do for you well.