I'm trying to create examples of all the different ways to write functions and function type definitions in TypeScript.
One requirement is these examples must work with strict mode (noImplicitAny
, etc) enabled.
If I'm missing anything, please add comments below with examples. I'll eventually put this into a blog post.
Keep in mind that there are TONS of combinations of different syntaxes. I only want to include those which are less obvious combinations or unique in some way.
// inferred return type
function sum(a: number, b: number) {
return a + b
}
// defined return type
function sum(a: number, b: number): number {
return a + b
}
const sum = function sum(a: number, b: number) {
return a + b
}
const sum = function(a: number, b: number) {
return a + b
}
const sum = (a: number, b: number) => {
return a + b
}
const sum = (a: number, b: number) => a + b
const sum = (a: number, b: number): number => a + b
const sum = (a: number, b: number): number => a + b
You can also add a type annotation next to the variable, and then the function itself will assume those types:
const sum: (a: number, b: number) => number = (a, b) => a + b
And you can extract that type:
type MathFn = (a: number, b: number) => number
const sum: MathFn = (a, b) => a + b
Or you can use the object type syntax:
type MathFn = {
(a: number, b: number): number
}
const sum: MathFn = (a, b) => a + b
Which can be useful if you want to add a typed property to the function:
type MathFn = {
(a: number, b: number): number
operator: string
}
const sum: MathFn = (a, b) => a + b
sum.operator = '+'
This can also be done with an interface:
interface MathFn {
(a: number, b: number): number
operator: string
}
const sum: MathFn = (a, b) => a + b
sum.operator = '+'
And then there's declare function
:
TODO (I'm not sure I understand this myself yet).
Given the interface:
interface Foo {
bar: string;
}
You can write the following function to reasonably assert that x
is a Foo
:
function isFoo(x: any): boolean {
return typeof x.bar === string;
}
By using the return signature here x is Foo
rather than boolean
, we can signal TypeScript to know our parameter's type:
function isFoo(x: any): x is Foo {
return typeof x.bar === string;
}
function baz(x: any) {
if (isFoo(x)) {
// inside this if, ts will give type-safety as it knows x is of Type Foo
console.log(x.bar);
}
}
This can be especially helpful in 'splitting' a union type:
function baz(x: Foo | Buzz) {
if (isFoo(x)) {
// inside this if, ts will give type-safety as it knows x is of type Foo
console.log(x.bar);
return;
}
// TS now knows x must be of type Buzz here!
doSomethingYouCouldOnlyDoToABuzzObj(x);
}
TODO
TODO
Object method:
const math = {
sum(a: number, b: number): number {
return a + b
},
}
Property as function expression:
const math = {
sum: function sum(a: number, b: number): number {
return a + b
},
}
Property as arrow function expression (whith implicit return):
const math = {
sum: (a: number, b: number): number => a + b,
}
Unfortunately, to extract the type you can't type the function itself, you have to type the enclosing object:
type MathFn = (a: number, b: number) => number
const math: {sum: MathFn} = {
sum: (a, b) => a + b,
}
Furthermore, if you want to add a property on it like above, then you have to extract the function definition as well:
type MathFn = {
(a: number, b: number): number
operator: string
}
const sum: MathFn = (a, b) => a + b
sum.operator = '+'
const math = {sum}
You may have noticed that this example is identical to an example above with only the addition of the const math = {sum}
. So yeah, there's no way to do all this inline with the object declaration.
TODO
TODO
TODO
TODO
TODO
TODO