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 narrowing with foo.constructor #16035

Open
calebegg opened this issue May 23, 2017 · 10 comments
Open

Type narrowing with foo.constructor #16035

calebegg opened this issue May 23, 2017 · 10 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@calebegg
Copy link

TypeScript Version: 2.3.1

Code

class FooTask {
  foo: number;
}

class BarTask {
  bar: number;
}

type taskType = FooTask|BarTask;

function createEvent(task: taskType) {
  if (task instanceof FooTask) {
    task.foo; // Works.
  }

  switch (task.constructor) {
    case FooTask:
      task.foo; // Fails.
  }
}

It would be nice if the second worked like the first; narrowed the type of task appropriately.

@RyanCavanaugh RyanCavanaugh added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels May 23, 2017
@glebm
Copy link

glebm commented Oct 21, 2017

At first I though this was because T.constructor is not of type T (#3841), but looks like that's not the only issue:

class A {
    'constructor': typeof A;
    a() { }
}
class B {
    'constructor': typeof B;
    b() { }
}

function f(x: A | B) {
    switch (x.constructor) {
        case A:
            x.a();  // Fails: not narrowed
        case B:
            x.b();  // Fails: not narrowed
    }
}

@glebm
Copy link

glebm commented Oct 27, 2017

@RyanCavanaugh What kind of feedback is this awaiting?

@mhegazy
Copy link
Contributor

mhegazy commented Oct 27, 2017

What kind of feedback is this awaiting?

We would like to get hear more user requests in favor of supporting this features

@ExE-Boss
Copy link
Contributor

You need to add break statements:

 function f(x: A | B) {
 	switch (x.constructor) {
 		case A:
 			x.a();
+			break;
  		case B:
 			x.b();
+			break;
 	}
 }

Also, another issue is that TypeScript doesn’t do narrowing using === on objects.

@karol-majewski
Copy link

I needed it a few times now. A use case from today: applying a strategy based on a runtime type.

let whitelist: string[] | RegExp | ((location: Location) => boolean);

let path = '/'
whitelist = [path];

((): boolean => {
  switch (whitelist.constructor) {
    case Array:
      return whitelist.includes(path);
    case RegExp:
      return path.match(whitelist) !== null;
    case Function:
      return whitelist(location);
  }
})()

TypeScript Playground

Such code is both concise and very readable. Wouldn't it be nice if elegance was complemented with type safety? 😢

@murbanowicz
Copy link

Is there any chance it will be fixed?

@ukstv
Copy link

ukstv commented Sep 7, 2022

Oh, I can add +1 to this feature request. Definitely needed in reactive programming.

@matthew-dean
Copy link

For some reason I thought TypeScript already had a feature of type narrowing via constructor, and it sort of does, but today I tried:

    const images = this.productImages // this is string | Map<string, string>
    if (images.constructor === String) {
      return images // TypeScript correctly identifies this as a string
    }
    return images.has(ImageConstants.Large). // TS error: Property 'has' does not exist on type 'string | Map<string, string>'
      ? images.get(ImageConstants.Large)
      : images.get(ImageConstants.Medium)

I take it that's because there are edge cases where a string can have a constructor from something other than String, but it would be nice to be able to tell TypeScript that that's never going to happen.

@mackuba
Copy link

mackuba commented May 20, 2024

Bumping this up, this still doesn't seem to work…

@Lukortech
Copy link

+1 as I am creating a simple game where spells or hands can be thrown.
I am trying to identify the type of action and adding "type":"meele" to a class feels inadequate if I could use constructor with switch case.

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests