I'm writing a library and I want to port it to typescript.
Currently it look something like that:
const is = value => {
... do some returns here
}
is.number = x => typeof x === 'number'
is.bla = x => typeof x === 'bla'
and so on.
I have wrote an interface describing is
and all its methods.
type TypeQueryMethod = (val: any) => boolean;
interface Is {
(val: any): string;
undefined: TypeQueryMethod;
null: TypeQueryMethod;
...
}
When I try to mark is
with the type: const is: Is = value => ...
It throws an error:
Type '(value: any) => string' is not assignable to type 'Is'.
Property 'undefined' is missing in type '(value: any) => string'.
Which makes sense because the declaration of the object is split.
How do you construct such an object that is both a method, and has methods?
Update for TypeScript 3.1+
TypeScript 3.1 introduced support for declaring properties on functions, to allow you to do this the way you were doing it to begin with:
const is: Is = (val: any) => typeof val; // okay
is.undefined = (val: any) => typeof val === 'undefined';
is.null = (val: any) => (val === null)
For TypeScript versions before 3.1:
If you want to make the type checker happy, you can use Object.assign()
to return a fully-formed Is
object without building it in stages:
const is: Is = Object.assign(
(val: any) => typeof val,
{
undefined: (val: any) => typeof val === 'undefined',
null: (val: any) => (val === null)
// ...
}
);
Of course, if you don't want to change the structure of your code, then you can do as @Saravana suggests and use a type assertion to just inform the type checker that is
is definitely an Is
, even though it technically isn't one until you're done building it.
Either way works, but I prefer the Object.assign()
method because the type checker will warn you if you neglect to implement something:
// error, "undefined" is missing
const is: Is = Object.assign(
(val: any) => typeof val,
{
null: (val: any) => (val === null)
// ...
}
);
while the type assertion method will not:
const is = ((val: any) => typeof val) as any as Is;
is.null = (val) => val === null;
// no error
whereas the type assertion method will not. It's up to you.
Playground link to code
You cannot implement a function as well as its properties at the same time. You can define the function first and assert it to Is
and define the rest of the methods:
const is = ((val: any) => typeof (val)) as any as Is;
is.null = (val) => true;
is.undefined = (val) => true;
Or use a factory function to create Is
:
function createIs(): Is {
const is = ((val: any) => {
return "";
}) as Is;
is.null = (val) => true;
is.undefined= (val) => true;
return is;
}
const is: Is = createIs();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With