Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: allow type predicates to be inferred when satisfies boolean is present #60778

Open
6 tasks done
kirkwaiblinger opened this issue Dec 16, 2024 · 2 comments Β· May be fixed by #60782
Open
6 tasks done

Suggestion: allow type predicates to be inferred when satisfies boolean is present #60778

kirkwaiblinger opened this issue Dec 16, 2024 · 2 comments Β· May be fixed by #60782
Labels
Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Milestone

Comments

@kirkwaiblinger
Copy link

kirkwaiblinger commented Dec 16, 2024

πŸ” Search Terms

inferred type predicates, satisfies, return type

βœ… Viability Checklist

⭐ Suggestion

I would like to allow type predicates to be inferred when the returned value is constrained by a satisfies boolean expression.
Concretely, I think this code should be legal:

const a: Array<number> = [1, 2, null, 3].filter(x => (x != null) satisfies boolean)

πŸ“ƒ Motivating Example

I am a big fan of explicitly typing any and all function declarations. So, I would never omit the return type on a function like

function isEmptyString(x: unknown): x is '' {
    const rv = x === '';
    return rv;
}

However, with inferred type predicates, it's actually safer to omit the return type, since user-defined type predicates can be totally unsafe:

function isEmptyString(x: unknown): x is '' {
    // whoops
    const rv = x !== '';
    return rv;
}

In other words, the safer code is

function isEmptyString(x: unknown) {
    const rv = x === '';
    return rv;
}

However, this is no longer visually explicit about what it's returning. And what's to stop future-me from making a typo and returning a non-boolean, completely changing the function's applicability.

Therefore, I'd like to be able to write

function isEmptyString(x: unknown) {
   const rv = x === '';
   return rv satisfies boolean;
}

This is both visually clear and easily analyzable by tooling. For example, at typescript-eslint we'd like to implement typescript-eslint/typescript-eslint#9764, but without having an unresolvable conflict with explicit-function-return-type. Allowing a single-return satisfies boolean could be a good way to create a statically analyzable exception for explicit-function-return-type that also allows you to enforce writing boolean-returning functions that otherwise would be syntactically eligible for inferred type predicates to be written without the explicit return type. We have precedent for something similar being familiar to the community in typescript-eslint/typescript-eslint#10231, where a satisfies expression is used to constrain but not change the return type of a function.

πŸ’» Use Cases

  1. What do you want to use this for?
  2. What shortcomings exist with current approaches?
  3. What workarounds are you using in the meantime?
    • Not taking advantage of inferred return types in many cases.

Note - an alternative, more general, approach could be to have a return type syntax like so:

const a: Array<number> = [1, 2, null, 3].filter((x): satisfies boolean => x != null)

This would indicate that the return type is constrained, but will still result in the more specific return type. This might also be useful in cases where a function is passed to a generic, or allowing a single satisfies constraint to apply to multiple return points, like

function returnsOneOrTwo(): satisfies number {
  if (Math.random() > 0.5) {
    return 1;
  } else {
    return 2;
  }
}

However, a) I don't think these are mutually exclusive, and b) the proposed solution does not require new syntax, whereas the alternate solution does.

@kirkwaiblinger kirkwaiblinger changed the title Allow type predicates to be inferred when satisfies boolean is present Suggestion: allow type predicates to be inferred when satisfies boolean is present Dec 16, 2024
@jcalz
Copy link
Contributor

jcalz commented Dec 16, 2024

If satisfies doesn't do what you want, you can usually work around it with a helper function (which is how people got satisfies-like behavior before TS4.9):

const satisfiesBoolFunc = <F extends (...arg: any) => boolean>(f: F) => f

const a: Array<number> = [1, 2, null, 3].filter(satisfiesBoolFunc(x => (x != null)))

Playground

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Experience Enhancement Noncontroversial enhancements Help Wanted You can do this labels Dec 16, 2024
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Dec 16, 2024
@RyanCavanaugh
Copy link
Member

I don't see any reason not to

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants