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

Type Guards are lost when using currying libraries #16410

Closed
sbking opened this issue Jun 9, 2017 · 2 comments
Closed

Type Guards are lost when using currying libraries #16410

sbking opened this issue Jun 9, 2017 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@sbking
Copy link

sbking commented Jun 9, 2017

TypeScript Version: 2.3.4

TL;DR: When a type guard function is passed to a higher order function with generics, the type guard information is lost and simply turned into boolean.

Code

import { curry } from 'lodash'
// import { curry } from 'ramda' // same behavior

interface Validator<T, V extends T> { (input: T): input is V }
interface Car { speed?: number }
interface FastCar extends Car { speed: number }

const isFastCar = curry(function (
  minSpeed: number, // some configuration setting that needs to be injected
  car: Car
): car is FastCar {
  return car.speed !== undefined && car.speed >= minSpeed
})

function filter<T, V extends T> (validate: Validator<T, V>, list: T[]): V[] {
  const results: V[] = []
  for (const item of list) {
    if (validate(item)) results.push(item)
  }
  return results
}

const cars: Car[] = [{ speed: 30 }, {}, { speed: 60 }, { speed: 45 }, { speed: 0 }, { speed: 75 }]
const fastCars: FastCar[] = filter<Car, FastCar>(isFastCar(55), cars)

Expected behavior:
The isFastCar type guard information (car is FastCar) should be preserved in the curried function, as if the isFastCar function had been manually curried:

const isFastCar = (minSpeed: number) => (car: Car): car is FastCar => {
  return car.speed !== undefined && car.speed >= minSpeed
}

fastCars would end up being [{ speed: 60 }, { speed: 75 }]

Actual behavior:
Error: Argument of type 'CurriedFunction1<Car, boolean> is not assignable to parameter of type 'Validator<Car, FastCar>'. Signature '(): CurriedFunction1<Car, boolean>' must have a type predicate.

The answer may simply be "just manually curry instead of using a library", but in some real cases with longer type assertions and more arguments, manually currying like this becomes unwieldy, and it becomes impossible to supply multiple arguments or use the currying placeholder features that libraries like ramda and lodash provide.

@mhegazy mhegazy added the Needs Investigation This issue needs a team member to investigate its status. label Aug 29, 2017
@mhegazy
Copy link
Contributor

mhegazy commented Feb 9, 2018

The type guard is not maintained by curry. I think you are looking for #10734

@mhegazy mhegazy added Duplicate An existing issue was already created and removed Needs Investigation This issue needs a team member to investigate its status. labels Feb 9, 2018
@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants