Edit
Per @Thomas comment, in newer TS compilers, we can simply do:
const foo = <T,>(x: T) => x;
Original Answer
The full example explaining the syntax referenced by Robin... brought it home for me:
Generic functions
Something like the following works fine:
function foo<T>(x: T): T { return x; }
However using an arrow generic function will not:
const foo = <T>(x: T) => x; // ERROR : unclosed `T` tag
Workaround: Use extends on the generic parameter to hint the compiler that it's a generic, e.g.:
const foo = <T extends unknown>(x: T) => x;
Answer from jbmilgrom on Stack OverflowEdit
Per @Thomas comment, in newer TS compilers, we can simply do:
const foo = <T,>(x: T) => x;
Original Answer
The full example explaining the syntax referenced by Robin... brought it home for me:
Generic functions
Something like the following works fine:
function foo<T>(x: T): T { return x; }
However using an arrow generic function will not:
const foo = <T>(x: T) => x; // ERROR : unclosed `T` tag
Workaround: Use extends on the generic parameter to hint the compiler that it's a generic, e.g.:
const foo = <T extends unknown>(x: T) => x;
If you're in a .tsx file you cannot just write <T>, but this works:
const foo = <T, >(x: T) => x;
As opposed to the extends {} hack, this hack at least preserves the intent.
Specify return type in TypeScript arrow function - Stack Overflow
Type for parameter in TypeScript Arrow Function - Stack Overflow
is it possible to type a named function the way a arrow function is typed?
[AskJS] why are arrow functions used so universally nowdays? What's the benefit over named functions/function keyword?
Videos
First, consider the following notation from your original question:
export const addTodo3 = (text: string) => <AddTodoAction>({
type: "ADD_TODO",
text
})
Using this notation, you typecast the returned object to the type AddTodoAction. However, the function's declared return type is still undefined (and the compiler will implicitly assume any as return type).
Use the following notation instead:
export const addTodo3 = (text: string): AddTodoAction => ({
type: "ADD_TODO",
text: text
})
In this case, omitting a required property will yield the expected compiler error. For example, omitting the text property will generate the following (desired) error:
Type '{ type: "ADD_TODO"; }' is not assignable to type 'TodoAction'.
Type '{ type: "ADD_TODO"; }' is not assignable to type 'DeleteTodoAction'.
Types of property 'type' are incompatible.
Type '"ADD_TODO"' is not assignable to type '"DELETE_TODO"'.
Also see the playground example.
There are 2 ways of achieving this with proper typing and minimal code:
interface AddTodoAction {
type: "ADD_TODO",
text: string
};
// Because the this keyword works different in arrow functions these
// 2 implementations are different in some cases:
// arrow function form/ function expression
const addTodo1 = (text: string): AddTodoAction => ({
type: "ADD_TODO",
text: text
})
// function declaration form
function addTodo2 (text: string): AddTodoAction {
return ({
type: "ADD_TODO",
text: text
})
}
Now the TS compiler can check the returned types. For example:
const todo = addTodo1('hi');
// Following gives TS compile time error
// addTodo1 returns AddTodoAction which does not have id on the type
const id = todo.id // Property 'id' does not exist on type 'AddTodoAction'.
Hi all,
I recently was looking at the Sveltekit hooks documentation and noticed that they write their functions in both arrow functions and named functions.
What made me boggle my brain for a moment is that their arrow functions had a typed argument, while a named function did not (and resulted in red squigglies in IDE). When it dawned on me that it was not the arrow function that was typed but the constvariable, it made me think of how one would implement the same as a named function. So far I only came up with the idea to type the arguments, and the return value (or have it inferred).
tldr: is it possible to type a named function (without adding type info individually to the arguments and return value(?
type MyFnArgs = { myNum: number, myString: string }
type MyFnReturnValue = void
type MyFn = ({ myNum, myString }: MyFnArgs) => MyFnReturnValue
const myArrowFn: MyFn = ({ myNum, myString }) => {
console.log("arrow function with typed args")
}
function myNamedFn({ myNum, myString }) {
console.log("named function with UNtyped args")
}
function myTypedNamedFn({ myNum, myString }: MyFnArgs): MyFnReturnValue /* could be inferred */ {
console.log("named function with typed args")
}https://www.typescriptlang.org/play?#code/C4TwDgpgBAsiBiA7AggJwOYGcoF4oG8oBbEAOQFciAuKRSgIwlQBpiQBlYVAS0XRsxde6KAF8AUKEiwEiAEoRg5VIgBqAQwA25aHgBuAe24ATcZPDQ4SXFAAUhEhSKsSnHnzE0rKDJgCUuAB8MkgKSioa2hBmAMYGiIJsaKgGAO5IXrI29mxOLhxCHqIBOMH44lBQcQkGmhAAdJoG6LYAROqoKalQAGbkiDHA3PFQqdzAABZQUhDGUB1YrX7iEuJ9A0MjjupEs0g5jpT5bsJiAeWV1Zi1DU0trYg7s739g8OIo+NTAKqkM3MLTBLFZmdZvLYgAAqFmMpCexn2DjIRzYJyKmSQaCwfgx8kUyjUWh0UAA9AAqKoGciaOaMKC8HpMVDPMkkggVSk1OqNZptR67OZgzYfMaTaYw+a+YGiIA