Reputation: 500663
In TypeScript, what exactly is type '{}'
and how does it relate to other built-in types?
For example, the last line of the following example gives Type '{}' is not assignable to type 'number'
, and I am not completely clear on what type {}
is in this context, or indeed how it comes about:
// A function taking no arguments and returning T
type NoArgsFn<T> = () => T;
// An instance of NoArgsFn<number>
function get_the_answer(): number {
return 42;
}
// Call the supplied function and return its value
function call<T, Fn extends NoArgsFn<T>>(fn: Fn): T {
return fn();
}
// Expect this to be equivalent to `let the_answer: number = 42', but
// instead get "Type '{}' is not assignable to type 'number'"
let the_answer: number = call(get_the_answer);
Upvotes: 28
Views: 20229
Reputation: 9330
The {}
is a type that can be assigned anything except null
and undefined
(=non-nullish value).
It does NOT represent an object literal without properties. If you wanted that use something like Record<PropertyKey, never>
instead.
let value: {};
value = 5;
value = "Hello World";
value = ["banana", "apple", "orange"];
value = () => true;
value = null;
//~~~ Type 'null' is not assignable to type '{}'.
value = undefined;
//~~~ Type 'undefined' is not assignable to type '{}'.
Upvotes: 7
Reputation: 741
type {}
Consider the object type { id: number, name: string }
, which represents a 2-field object. Legal values of this type include { id: 1, name: "Foo" }
and { id: 2, name: "Bar" }
.
The type object {}
represents a 0-field object. The only legal value of this type is an empty object: {}
.
So the value { id: 1, name: "Foo" }
is of type { id: number, name: string }
, and the value {}
(i.e. an empty object) is of type {}
.
The error seems to be a bug in the TypeScript compiler (I submitted an issue here). It fails to infer the type arguments in the call to call
. You can work around this by explicitly specifying the type arguments:
let the_answer: number = call<number, NoArgsFn<number>>(get_the_answer);
But it's simpler and more straightforward to use a single type argument instead, as @NitzanTomer suggested:
function call<T>(fn: NoArgsFn<T>): T {
return fn();
}
EDIT: I issue I submitted was closed as a duplicate of #7234 which is to be fixed before the release of TypeScript 2.0.
Upvotes: 11
Reputation: 644
As far as I know, {}
casts directly to a hash map like usage. You can only use keyed properties, versus the dot notation.
var o:{} = {}
should be equivalent to
var o:{[key:string]:any} = {}
So
o.x = 5; //fails
But
o['x'] = 5; //succeeds
Upvotes: 3
Reputation: 164277
You need to have your call function like this:
function call<T>(fn: NoArgsFn<T>): T {
return fn();
}
In your original call
function you had 2 generic types which you did not pass when calling the function and the compiler failed to infer what types they are.
Type {}
is an object literal (as far as I'm aware), and so you can face the same error like this:
var o = {};
var n: number = o; // Error: Type '{}' is not assignable to type 'number'
I'm not exactly sure why the compiler inferred that the function returns {}
in your example.
Upvotes: 5