The empty object is TypeScript's weirdest type

  Рет қаралды 26,656

Matt Pocock

Matt Pocock

Күн бұрын

Пікірлер: 66
@macr76
@macr76 Жыл бұрын
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.
@lasfito
@lasfito Жыл бұрын
Yet typeof null == 'object'
@macr76
@macr76 Жыл бұрын
@@lasfito Yes, but just because specs says so. This is generally considered mistake/flaw in JavaScript and doesn't change the fact that null is primite and one of two primitives which doesn't have object representation.
@marcus8784
@marcus8784 Жыл бұрын
This is called autoboxing, primitives in javascript does not have methods, but for simplicity JavaScript wraps it with for example String object if you try to access .toUppercase method on a string primitive. This is why we hear often the term “everything in JavaScript is an object”. It’s almost true. Without this, imagine how annoying it would be, creating this for every string you want to access String methods on: const string4 = new String("A String object"); Same for Number and Boolean. But not undefined or null! That’s why this makes sense
@marcus8784
@marcus8784 Жыл бұрын
You’re explanation was a lot quicker though 😂👍
@rafadydkiemmacha7543
@rafadydkiemmacha7543 Ай бұрын
It doesn't excuse this stupid, confusing type.
@EthanStandel
@EthanStandel Жыл бұрын
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.
@ex-xg5hh
@ex-xg5hh Жыл бұрын
Another interesting use of {} is to lower inference priority for type parameters. declare function f(arg1: T, arg2: T): void f(1, 2) // OK, T inferred as 1 | 2 declare function f(arg1: T & {}, arg2: T): void f(1, 2) // ERROR, T inferred as 2 declare function f(arg1: T, arg2: T & {}): void f(1, 2) // ERROR, T inferred as 1 declare function f(arg1: T & {}, arg2: T & {}): void f(1, 2) // OK, T inferred as 1 | 2
@hicoop
@hicoop Жыл бұрын
Eslint has literally taught me more typescript than any blog or site haha. Even educates me on types like {}
@DEVDerr
@DEVDerr Жыл бұрын
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
@thetos
@thetos Жыл бұрын
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 to be more explicit.
@yumeyuki1944
@yumeyuki1944 Жыл бұрын
Honestly, I feel the TypeScript team could just get rid of this type, this can be used instead `NonNullable` and is a lot easier to understand.
@barneylaurance1865
@barneylaurance1865 Жыл бұрын
I think it would be confusing and too arbitrary to get rid of the empty object type. If you can have an object type with two properties, or one property why shouldn't you have an object type with no properties?
@yumeyuki1944
@yumeyuki1944 Жыл бұрын
@@barneylaurance1865 Then you use `Record`
@barneylaurance1865
@barneylaurance1865 Жыл бұрын
@@yumeyuki1944 That's an object with exactly zero properties, it's different to {} which is an object with at least zero properties which is what I'm talking about. Just like {foo: number} is an object with at least one property.
@svenyboyyt2304
@svenyboyyt2304 Жыл бұрын
​@@barneylaurance1865 Well you should be able to have an object type with 0 properties but you just said it it has 2 keys, it should have 2 keys, if it has 3, it has 3. So if it has 0 keys it should have zero keys. So then why can you assign anything other than null/undefined to it?
@svenyboyyt2304
@svenyboyyt2304 Жыл бұрын
​@@barneylaurance1865 It doesn't work as an object type with 0 properties though.
@moomoomamoo
@moomoomamoo 11 ай бұрын
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
@CYXXYC
@CYXXYC Жыл бұрын
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"
@barneylaurance1865
@barneylaurance1865 Жыл бұрын
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: {} = () => {};
@mattpocockuk
@mattpocockuk Жыл бұрын
True!
@Mitsunee_
@Mitsunee_ Жыл бұрын
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.
@MaxProgramming
@MaxProgramming Жыл бұрын
So apparently we have an option to use a pair of curly braces between "any" and "unknown". Kinda weird but works so 😅
@stancobridge
@stancobridge Жыл бұрын
Everything is an object even null, that's why... But typescript decides to ignore the null aspect of that story
@mattpocockuk
@mattpocockuk Жыл бұрын
null is not an object - it doesn't behave as an object in any meaningful sense. TS _does_ understand that typeof obj === 'object' might be 'object | null', though.
@stancobridge
@stancobridge Жыл бұрын
@@mattpocockuk Alright cool
@marcus8784
@marcus8784 Жыл бұрын
Looking how JavaScript primitives work, this makes sense. If we take autoboxing into account, the only things that are not objects are null and undefined. Without autoboxing, primitives in javascript does not have methods, but for simplicity JavaScript wraps it with for example String object if you try to access .toUppercase method on a string primitive. This is why we hear often the term “everything in JavaScript is an object”. It’s almost true. Without this, imagine how annoying it would be, creating this for every string you want to access String methods on: const string4 = new String("A String object"); Same for Number and Boolean. But not undefined or null! That’s why this makes sense
@xtraszone
@xtraszone Жыл бұрын
So basically its non-nullish. I think its very useful
@soniablanche5672
@soniablanche5672 Жыл бұрын
It actually makes sense, everything that can have a property can be of type "{}", which is basically everything except null and undefined
@nomadshiba
@nomadshiba Жыл бұрын
this also works on c# if (foo is {})
@tririfandani1876
@tririfandani1876 Жыл бұрын
How about "object" type? It's kinda confusing to me, we have "Record", "{}" and "object" to represent object types...
@ciach0_
@ciach0_ Жыл бұрын
the object type represents all values that are not primitive
@janhenckel
@janhenckel Жыл бұрын
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. 😇
@mattpocockuk
@mattpocockuk Жыл бұрын
That's more like providing an alias to an existing interface, so type Foo = Bar is correct.
@vladimircreator
@vladimircreator Жыл бұрын
Make object instead of {} and now it makes sense
@Alec.Vision
@Alec.Vision Жыл бұрын
"How do you represent any nonnullish type without 'any' or 'unknown'?" ...'something'?
@paoloose
@paoloose Жыл бұрын
Typescript devs really have to do insane things in order to conform Javascript specification and semantics
@dgcp354
@dgcp354 Жыл бұрын
hey matt, i was watching the last stream and what was the prompt thing you did with chatgpt
@punio4
@punio4 Жыл бұрын
The FPS seems wrong with your new setup and the audio is a bit off too.
@Nekroido
@Nekroido Жыл бұрын
I actually had to use this type for my redux-websocket library. The idea was to have an instance of a type that can gain new properties through a `register` method and have them statically type-hinted. The initial state is obviously an empty object, so I had to silence my linter and use `SocketApi`. Now I wanna see if using `Record` instead will still work.
@Nekroido
@Nekroido Жыл бұрын
Aight, the only thing that worked correctly was creating an empty object value as const: const emptyObject = {} as const; const api = { ... } as SocketApi; It's more declarative of what I'm trying to do here, but I'm not sure if I should stick with it, since it's a library project.
@xnomado
@xnomado Жыл бұрын
My eslint dont like {} instead i uneed to use that NonNullable
@RomanOstolosh
@RomanOstolosh Жыл бұрын
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
@rodingrajo998
@rodingrajo998 Жыл бұрын
ontology of code: god = {} man = undefined evil = null
@amansagar4948
@amansagar4948 Жыл бұрын
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
@culi7068
@culi7068 Жыл бұрын
The strangest type in my opinion is Intrinsic
@w01dnick
@w01dnick Жыл бұрын
Funny thing, typeof null is object in js but null is not assingable to {} in ts
@echobucket
@echobucket Жыл бұрын
Is this literally the same type as "Object"?
@KirkWaiblinger
@KirkWaiblinger Жыл бұрын
Yes
@bubble4525
@bubble4525 Жыл бұрын
Bro, by any chance, do you think the Dart language is better than JS&TS??
@mattpocockuk
@mattpocockuk Жыл бұрын
Maybe! But TS/JS will for sure get you a job faster.
@daleryanaldover6545
@daleryanaldover6545 Жыл бұрын
I am learning typescript so I could annotate my JSDoc comments
@rafadydkiemmacha7543
@rafadydkiemmacha7543 Ай бұрын
I hate this feeling when I find shit like this in languages or frameworks. It's so clearly confusing and annoying, they should get rid of it.
@TroyNiemeier
@TroyNiemeier Жыл бұрын
Why doesn't the {} type have an English keyword name, rather than the code symbols, which are also a value? (I'm someone with a lot of JS experience, but zero TS experience.)
@KirkWaiblinger
@KirkWaiblinger Жыл бұрын
It does. "Object" (not to be confused with "object"). Also Nonnullable will result in the same
@jwbonnett
@jwbonnett Жыл бұрын
Audio is out of sync
@mbuzogan
@mbuzogan Жыл бұрын
would you ever want to use it in a real project? it is super interesting but ... when you stumble upon something like that, in some code, it does the opposite of understanding what's going on :D
@syskall
@syskall Жыл бұрын
(Off-topic but you look really good with shaved head 👍)
@Keisuki
@Keisuki Жыл бұрын
I don't see anything weird about this. It acts exactly as we'd expect. Like an interface with no declared methods.
@svenyboyyt2304
@svenyboyyt2304 Жыл бұрын
Ok but then why can you make it not be an object then? And why can you give it keys?
@Keisuki
@Keisuki Жыл бұрын
@@svenyboyyt2304 Just like how my object { name: "Keisuki", occupation: "Developer } is a valid value for the interface { name: string; } So too is the object { name: "Keisuki" } a valid value for the interface { }
@Keisuki
@Keisuki Жыл бұрын
@@svenyboyyt2304 As for why you can make it not be an object... Try the following code. It's valid: interface HasLength { length: number; } export const hs: HasLength = [] Nothing about an interface in typescript states that the value *must* be an object, just that it must have the properties described by the interface. An array, a boolean, a number, they all satisfy the constraints of the interface {}, because it doesn't apply any constraints, except that the value is defined.
@aniketnangare904
@aniketnangare904 Жыл бұрын
This is not your voice it is looking like generated
@mattpocockuk
@mattpocockuk Жыл бұрын
Don't know what to tell you - it's my voice!
Infer is easier than you think
13:38
Matt Pocock
Рет қаралды 90 М.
as const: the most underrated TypeScript feature
5:38
Matt Pocock
Рет қаралды 119 М.
Новый уровень твоей сосиски
00:33
Кушать Хочу
Рет қаралды 4,6 МЛН
From Small To Giant Pop Corn #katebrush #funny #shorts
00:17
Kate Brush
Рет қаралды 68 МЛН
Cute
00:16
Oyuncak Avı
Рет қаралды 12 МЛН
The joker favorite#joker  #shorts
00:15
Untitled Joker
Рет қаралды 20 МЛН
Enums considered harmful
9:23
Matt Pocock
Рет қаралды 206 М.
Function Overloading in TypeScript (I was wrong)
10:24
Andrew Burgess
Рет қаралды 13 М.
NextJS to Rails: The code that powers our new marketing site
14:30
Adam McCrea
Рет қаралды 1,1 М.
Generics: The most intimidating TypeScript feature
18:19
Matt Pocock
Рет қаралды 176 М.
The TypeScript feature I never use
10:49
Andrew Burgess
Рет қаралды 11 М.
The TSConfig Cheat Sheet
5:36
Matt Pocock
Рет қаралды 35 М.
Why use Type and not Interface in TypeScript
14:12
ByteGrad
Рет қаралды 206 М.
The Most Legendary Programmers Of All Time
11:49
Aaron Jack
Рет қаралды 563 М.
Premature Optimization
12:39
CodeAesthetic
Рет қаралды 808 М.
Новый уровень твоей сосиски
00:33
Кушать Хочу
Рет қаралды 4,6 МЛН