4

If I create a generic class

class Generic<T> {
     prop: T;
}

It won't allow me to type something without specifying T in the type

// Generic type 'Generic<T>' requires 1 type argument(s).
const val: Generic = new Generic(); 

But if I use type inference, it doesn't complain, it lets me instantiate it

const val = new Generic();
// field prop is not of type any, we can't access any properties on it
// val.prop.anything -> Compiler error
// val.prop.toString() -> No error, is it a string?
// val.prop.length -> Compiler error, not a string, just assumes that everything has a toString (based on boxing)

Is this behavior specified? What is the reasoning behind this?

Background

Angular2 has an EventEmitter which requires a type of the argument for the event. However, for some events, you don't pass any arguments, in which case we had been using EventEmitter<void>. However, I just noticed that you can just define emitters without specifying type and new EventEmitter() works. The drawback of this approach is that the compiler won't complain if you pass an argument to emitter.emit('something'). This is not what I'm interested in, just background so readers can understand where the question came from.

Playground https://www.typescriptlang.org/play/#src=class%20Generic%3CT%3E%20%7B%0D%0A%20%20%20%20prop%3A%20T%3B%0D%0A%7D%0D%0A%0D%0Aconst%20val%3A%20Generic%20%3D%20new%20Generic()%3B%0D%0A%0D%0Aconst%20val2%20%3D%20new%20Generic()%3B%0D%0A%0D%0Aval2.prop.test%20%3D%201%3B

4
  • 2
    Since generics are not available at run time (it will all become pure Javascript), I can imagine that the new Generic() line is allowed since you might use exactly this line in Javascript that imports a transpiled library. In short: for compatibility to Javascript. Commented Dec 13, 2017 at 16:03
  • Which version of typescript are you using? I get an error when try to compile your code. Generic type 'Generic<T>' requires 1 type argument(s). Commented Dec 13, 2017 at 16:04
  • @Sebastian I can't make sense out of what you're saying... Any links that validate your thoughts? If that's allowed, now you have a property without a type, that doesn't seem to be compatible with JavaScript because you'd have to cast prop to be something if you want to use it? Commented Dec 13, 2017 at 16:04
  • @Duncan I'm using the online playground, I would assume it's latest? Commented Dec 13, 2017 at 16:05

1 Answer 1

3

The following two statements are equivalent...

const val: Generic<{}> = new Generic();
const val2 = new Generic();

In the first case, the type argument that is omitted on the right-hand side is inferred from the type on the left-hand side.

In the second case, you end up with an object type, because nothing more specific can be inferred.

The rule here is that the type of the variable must have the generic type parameter satisfied. When you use const val: Generic = new Generic(); the type parameter is not satisfied - you can't ask for it to be inferred because you have decided to annotate the variable.

So the two allowable scenarios are:

  1. Specify the (entire) type yourself with a type annotation
  2. Allow the (entire) type to be inferred by the compiler

To make your later example work, you have two options.

Option 1... if you really don't want to limit the type, go dynamic...

const val2 = new Generic<any>();
val2.prop.test = 1;

Or... Option 2... if you do want to limit the type, specify it.

const val2 = new Generic<{ test: number }>();
val2.prop.test = 1;

And finally, in many contexts, you don't need to specify the type argument as it can be inferred contextually.

Sign up to request clarification or add additional context in comments.

3 Comments

const val: Generic<string> = new Generic<string>(); ?
He could also make it default to any, that way it doesn't have to be specified explicitly. class Generic<T = any> { ... }
@JeffMercado For my specific case, that will stop throwing errors when people pass an argument to the emit call emitter.emit('what') // should throw error

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.