The empty object is TypeScript's weirdest type

preview_player
Показать описание
Full article here:

Become a TypeScript Wizard with my free beginners TypeScript Course:

Follow Matt on Twitter

Join the Discord:

Рекомендации по теме
Комментарии
Автор

This is actually mentioned in Microsoft TypeScript FAQ. If you think of it in that way, it makes perfectly sense, because in JavaScript everything except for null and undefined have object representation and therefore everything has all required member (which are none) of "{}" type.

macr
Автор

I like to think of it as

type Box = {};
declare const box: Box;

There can be `"something" in box` but at the time of declaration we don't know what's in it. We only know it's a box. Whereas null & undefined aren't boxes because they can't hold any value and there's no way to look inside.

EthanStandel
Автор

Eslint has literally taught me more typescript than any blog or site haha. Even educates me on types like {}

hicoop
Автор

For me the semi-correct (but not exact) reason could be that in JS - Booleans, Strings and Numbers are also objects with some methods, so using `{}` as a type could define any object (so Booleans, Strings and Numbers too)
I know that it's not exactly true, because using simple `typeof Boolean()` or `typeof 'true` will return 'boolean', but still... it's kinda an object, since you can still access it's constructor and even call their methods like `toString()` or `valueOf()`

Which is not the thing for nulls and undefinedes, so it almost matches what's going on here (and why it's erroring only while passing null or undefined

DEVDerr
Автор

Another interesting use of {} is to lower inference priority for type parameters.

declare function f<const T>(arg1: T, arg2: T): void

f(1, 2) // OK, T inferred as 1 | 2


declare function f<const T>(arg1: T & {}, arg2: T): void

f(1, 2) // ERROR, T inferred as 2


declare function f<const T>(arg1: T, arg2: T & {}): void

f(1, 2) // ERROR, T inferred as 1


declare function f<const T>(arg1: T & {}, arg2: T & {}): void

f(1, 2) // OK, T inferred as 1 | 2

ex-xghh
Автор

the {} type is fairly useful when used on generic constraints to ensure the type is not null or undefined (because it would make sense), but anything else goes. Though in general, for that use case, I follow ESLint's recommendation of using NonNullable<unknown> to be more explicit.

thetos
Автор

Ran into a conversation about `{}` and went straight to this video to explain how it works and what it means. This is by far the best explanation on `{}`. Love it

moomoomamoo
Автор

2023 and I still have no clue how to make a generic that can extend any plain object (so no string, bool, number, Array, Map, Set and so on). `object` gets close, but does allow arrays and such.

Mitsunee_
Автор

And how about the type 'object' can it be used instead of literal type declaration there?

Also I saw it being used in Simplify generic util in the type-fest library to uncover internal structure of an interface or a type

RomanOstolosh
Автор

i guess its clearly because when you have a type that goes like {property1: ..., property2: ..., ...}, it has to be a value that has properties [property1, property2, ...], and if you have a type that goes {}, it has to be a value that has properties [], which is like "no properties required, you may have them, but you dont have to"

CYXXYC
Автор

hey matt, i was watching the last stream and what was the prompt thing you did with chatgpt

dgcp
Автор

So apparently we have an option to use a pair of curly braces between "any" and "unknown".

Kinda weird but works so 😅

MaxProgramming
Автор

Well coincidently our codebase also have some union type that infered as {} | SomeObject, is there any way to exclude this {} ? Using exclude util is returning never

amansagar
Автор

What about extending an interface but not adding any new properties? Ala `interface Foo extends Bar {}`. Is that more similar to `type Foo = Bar` or `type Foo = Bar & {}`? Seems very strange to me. 😇

janhenckel
Автор

So empty object type is just an object that doesn't necessarily have any properties, any object. And the insight is that numbers, strings, bools etc are all objects.

And so are functions - this compiles:

const someFunction: {} = () => {};

barneylaurance
Автор

Everything is an object even null, that's why... But typescript decides to ignore the null aspect of that story

stancobridge
Автор

My eslint dont like {} instead i uneed to use that NonNullable<unknown>

xnomado
Автор

It actually makes sense, everything that can have a property can be of type "{}", which is basically everything except null and undefined

soniablanche
Автор

So basically its non-nullish.
I think its very useful

xtraszone
Автор

How about "object" type? It's kinda confusing to me, we have "Record", "{}" and "object" to represent object types...

tririfandani
visit shbcf.ru