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

can i rely on this weird yet handy behavior? if not what is a working alternative? #18074

Closed
zpdDG4gta8XKpMCd opened this issue Aug 27, 2017 · 7 comments
Labels
Bug A bug in TypeScript
Milestone

Comments

@zpdDG4gta8XKpMCd
Copy link

zpdDG4gta8XKpMCd commented Aug 27, 2017

i have a very complex generic function that depends on A, B, C, D with a lot of parameters that involve A | B | C | D one way or another , i want to save some time writing A | B | C | D every time by aliasing it type X = A | B | C | D unfortunately there is no place for such alias within the function signature, however i discovered a hack that seems to make it work:

const never: never = null as never;
function fn<A, B, C, D>(
  one: X, // <-- type of X is pulled out from the declaration within the function body
  another: X, 
  X: X = never // <-- thank to this the type X defined in function body is visible in the function signature
): void {
   type X = A | B | C | D;
}

i bet it's not how it was supposed to be working but this really saves me a ton of time in maintenance, please either:

  • allow type declarations in function signatures
  • or let this hack be (DON'T FIX IT!!!)

same problem is with interfaces and there is no hack like with functions, so i have to write this:

interface I<A, B, C, D> {
  doThis(one: A | B | C | D, another: A | B | C | D): void
  doThat(ones: (A | B | C | D)[], another: Promise<(A | B | C | D)[]>): void
  // ... you got the idea
}
  • so allow type aliases in interface declarations too!
interface I<A, B, C, D> {
  type X = A | B | C | D; // <-- i wish!
  doThis(one: X, another: X): void
  doThat(ones: X[], another: Promise<X[]>): void
  // ... you got the idea
}
@gcnew
Copy link
Contributor

gcnew commented Aug 27, 2017

I feel like I'm asking the obvious, but why not generic defaults?

function fn<A, B, C, D, X = A | B | C | D>(one: X, another: X): void {
   ...
}

@zpdDG4gta8XKpMCd
Copy link
Author

zpdDG4gta8XKpMCd commented Aug 28, 2017

because X defined as default generic X = A | B | C | D isn't assignable (in general case) to A | B | C | D, take a look:

const never: never = null as never;
function fn<A, B, C, D, X = A | B | C | D>(
  one: X,
  another: X,
  test: (value: A | B | C | D) => void
): void {
  test(one); // <-- bummer
}

@zpdDG4gta8XKpMCd
Copy link
Author

zpdDG4gta8XKpMCd commented Aug 28, 2017

this ugliness works tho:

const never: never = null as never;
function fn<A, B, C, D, X extends A | B | C | D = A | B | C | D>(
  one: X,
  another: X,
  test: (value: A | B | C | D) => void
): void {
  test(one);
}

@jcalz
Copy link
Contributor

jcalz commented Aug 28, 2017

Maybe it works for your use case, but the generic-default-with-constraint still only declares X as a subtype of A | B | C | D, so it's not quite the same as an alias:

Weird alias, works:

function fn<A, B, C, D>(
  a: A
  test: (value: X) => void // <-- X usable here
  X?: undefined // <-- this seems to pull X into visibility also
): void {
  type X = A | B | C | D;
  test(a); // works, A is assignable to X
}

Generic with constraint, broken:

function fn<A, B, C, D, X extends A | B | C | D = A | B | C | D>(
  a: A,
  test: (value: X) => void
): void {  
  test(a); // error! A is not assignable to X
}

Note that in using the "weird but handy" method, I don't think you need to make the X parameter of type X. A parameter named X of any type seems to bring the type X into scope (which must be a bug).

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Aug 28, 2017

"use strict";
function f(y = (x = 1)) {
  var x;
  console.log(x, y)
}
f();
VM420:2 Uncaught ReferenceError: x is not defined
    at f (<anonymous>:2:19)
    at <anonymous>:1:1

vars don't work that way, so it seems like it should be a bug, but I deeply sympathize with how downright annoying it is to deal with complicated local types.


Note that currently we seem to have an emit bug on the above code as well.

@DanielRosenwasser DanielRosenwasser added the Bug A bug in TypeScript label Aug 28, 2017
@zpdDG4gta8XKpMCd
Copy link
Author

zpdDG4gta8XKpMCd commented Aug 28, 2017

@jcalz you are right, damn, hacky way it is, @DanielRosenwasser it's not a bug but a useful feature, take off that bug label! ;)

@RyanCavanaugh
Copy link
Member

The above bug has been fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

7 participants