GithubHelp home page GithubHelp logo

Comments (5)

RyanCavanaugh avatar RyanCavanaugh commented on April 27, 2024 1

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.

fabiospampinato avatar fabiospampinato commented on April 27, 2024

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.

https://www.typescriptlang.org/play?ts=5.5.0-dev.20240318#code/FAFwngDgpgBAYgORgXhgCgJQoHwwAoBOA9gLYCWAzlADwCuAdgCZQBmZ9UjuAPjA82w6MA3MGABjIvQogYLegEYAXPCSoAhhTD1x6LMlwBvYDFMwCUELQL1RAX1ESpMufQBMKxChibtuzDgwxmbmltb0fEys7Jz2okA

from typescript.

Andarist avatar Andarist commented on April 27, 2024

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.

Andarist avatar Andarist commented on April 27, 2024

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.

RyanCavanaugh avatar RyanCavanaugh commented on April 27, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.