Comments (5)
This is just a bug. We have special logic in contextual typing to ensure that a function that would normally be inferred as void
return undefined
instead if needed:
type FN = () => undefined;
// Not an error
const fn1: FN = () => {
};
Something with the union with Promise is messing it up, probably because we also have logic to make the Promise case in specific also work:
type FN = () => Promise<undefined>;
// Also not an error
const fn1: FN = async () => {
};
Unions with other values don't seem to have this problem
from typescript.
Interestingly if the function is async now Promise<undefined>
is always the return type, even if I omit the return
statement entirely, which seems pretty inconsistent.
from typescript.
It's related to this 5.1 change. The linked PR mentions that:
Functions with an explicitly specified return type undefined aren't required to have return statements (similar to functions with an explicitly specified return type of void or any). Note that this does not apply to functions with union return types that include undefined.
I'm not sure what's the exact reason behind this but I find it confusing and inconsistent too. I get it that it might be easy to forget a return value in such cases. It feels like a potential lint rule for people who prefer explicit return undefined
. It's surprising that the typechecker complains here. At the very least the error message could mention how to fix this problem because at the moment it's not obvious what to do about it.
This is a reason why people write weird things when they actually want to allow those implicit undefined when the conceptual return type is meant to be a union that includes undefined
(taken from @types/react
):
declare const UNDEFINED_VOID_ONLY: unique symbol;
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };
type EffectCallback = () => void | Destructor;
Whereas if undefined
could be implied when dealing with unions this would be much simpler:
type Destructor = () => void;
function useEffect(cb: () => undefined | Destructor) {}
useEffect(() => {
// it would be perfect if this could be implied
return undefined;
});
// errors as expected
useEffect(() => {
return 10;
});
useEffect(() => {
// it works just fine
return () => {};
});
useEffect(() => {
return () => {
// we don't care about the return type here so it's allowed
return "foo";
};
});
from typescript.
Unions with other values don't seem to have this problem
Maybe we are talking about some other behaviors. I think the OP is reporting the same problem as the one showcased here:
type FN = () => string | undefined;
// Type '() => void' is not assignable to type 'FN'.
// Type 'void' is not assignable to type 'string | undefined'.(2322)
const fn1: FN = () => {
return;
};
// ok
const fn2: FN = () => {
return undefined;
};
// Not all code paths return a value.(7030)
const fn3: FN = () => {
if (Math.random()) {
return "";
}
};
The code that "converts" the inferred void
to undefined
is here and it doesn't use someType
(that would handle unions) to check if contextualReturnType
contains an undefined
type.
Unless you are saying that both of those should be errors:
type FN = () => Promise<undefined> | undefined;
// Type '() => void' is not assignable to type 'FN'.
// Type 'void' is not assignable to type 'Promise<undefined> | undefined'.(2322)
const fn1: FN = () => {
return;
};
// ok
const fn2: FN = async () => {};
IIUC, this is not what OP's post is about though so the added "Bug"/"Help Wanted" labels make it confusing to me.
from typescript.
What I mean is that if the contextual type itself i a union with other types, that doesn't spoil the pot:
type FN = 42 | (() => undefined);
// Not an error
const fn1: FN = () => {
};
IIUC, this is not what OP's post is about though so the added "Bug"/"Help Wanted" labels make it confusing to me.
To clarify, this code should not have an error:
type FN = () => Promise<undefined> | undefined;
const fn1: FN = () => {
return;
};
Seems like using someType
in that linked code might be the right fix
from typescript.
Related Issues (20)
- Type alias circularly references itself (5.4 regression) HOT 1
- error TS2385: Overload signatures must all be public, private or protected. HOT 2
- `export type * ...` statements in `.d.ts` files do not work (5.4 regression) HOT 4
- HTMLFormElement disallows symbol keys HOT 5
- TypeScript language service cannot find subclass references/implementation of mixin methods
- when using ts.getJSDocTags, the value of @type is not returned. Is there any solution? HOT 1
- Compiler allows narrower method signature than implemented interface HOT 6
- Allow overload signatures to have different access levels HOT 3
- Watcher recursively watches irrelevant directories HOT 11
- Auto-closing of tags within curly braces `{}` does not work when parent element is same tag in JSX HOT 1
- Undocumented breaking change in 5.5.0-beta for reference directives HOT 3
- 5.5.0 regression - importHelpers do not work with moduleResolution: bundler HOT 1
- 5.5.0 inheriting outDir: ${configDir} does not automatically exclude it from compilation HOT 3
- isolatedDeclarations wrongly enabled in VSCode HOT 3
- ESNext Set methods HOT 1
- isolatedDeclarations should not have warning for functions that have no return statements HOT 4
- Trivia ownership documentation seems to be incorrect
- `--isolatedDeclarations` allows generator functions HOT 1
- Allow `--noCheck` on the CLI with top-level `--build`
- Union in template literal simplifying unexpectedly
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typescript.