#`object` extends `{ }`, `{ }` extends `object` - yet they differ

48 messages · Page 1 of 1 (latest)

eager shoalBOT
fast yacht
#

i believe that's an edge case

#

also fwiw:

// type {} -> any object with zero or more properties
// type object -> a value with Object in its prototype chain
{} means something you can access properties on, so anything non-nullish
object doesn't mean Object, object is just a non-primitive {}

tidal thistle
fast yacht
tidal thistle
#

yeah, fair enough

fast yacht
#

though primitives themselves don't have prototypes to begin with (by definition) so maybe that's up to interpretation 🤷

tidal thistle
#

also:

eager shoalBOT
#
const notAnError: object = new String('heh')
tidal thistle
#

(but that's not "auto"-boxing)

fast yacht
#

but then, anything with a prototype has Object in its prototype chain, because Object is the prototype root... so maybe then it doesn't make sense to say "prototype chain without Object"? idk...

tidal thistle
#

-# *except Object.create(null)

fast yacht
#

i wouldn't say that has a prototype

tidal thistle
#

okay fine, Object.create(Object.create(null))

fast yacht
#

oh god, i hate it.

tidal thistle
#

if i could wave a magic wand and make one breaking change to JS, making null prototypes the default for object literals would be a top contender

fast yacht
#

this feels so wrong.

tidal thistle
#

is that chrome's inspector? why doesn't it show Object methods when you expand the prototype (toString etc)?

fast yacht
#

because it's the empty prototype...?

tidal thistle
#

oh i misread, i thought those were two separate things you entered (Object.create(Object.create(null)) and {})

fast yacht
#

oh lol

tidal thistle
#

(also sorry jstandfast for taking over your help thread. feel free to steer things back on track if you have more questions)

coarse hull
#

@tidal thistle no worriess at all. Interesting questions, all of them. Here's a tangent of my own, which may or may not be helpful to you: later yesterday, after the original post, I bought a copy of Effective TypeScript and I'm finding it a splendid read.

tidal thistle
coarse hull
#

But going back to the original question - my mental model is that a type is a set of possible runtime values. When we say

TypeA extends TypeB

we can express it in many equivalent ways, including:

TypeA is a subset of TypeB

any value in the domain of TypeA is also a value in the domain of TypeB

so if object extends {} and {} extends object....

fast yacht
#

But going back to the original question - my mental model is that a type is a set of possible runtime values. When we say
right, that's generally how ts' type system is modelled

#

union/intersection are as is, extends is subset, unknown is universe, never is empty

tidal thistle
#

i agree with you that {} extends object should be false. more generally subtyping relations should form a partial order

fast yacht
#

but "generally" is pulling some weight here
ts has some exceptions; any and void exist somewhat outside the system (they have special rules) and certain checks directly violate what set theory would dictate

#

those exceptions tend to be for ease of use with common js patterns, rather than focusing on correctness

coarse hull
#

...without knowing anything about them, I'd expect that they're the same set. @fast yacht 100% agree - I'm definitely not saying "TS is wrong, I am so smart!"

tidal thistle
#

i think a lot of the weird edge cases in TS come from the fact that infinitely-sized sets are hard to deal with implementation-wise

fast yacht
coarse hull
#

I'm wondering what this unexpected behavior reveals about how things actually work, or what design choices where made, etc.

fast yacht
#

(but the set theory model still is really useful, it explains assignability of abstract and readonly well)

#

oh, also this is a really good example of why ts is unsound.

const x: {} = ""
const y: object = x;
```this is valid ts.
coarse hull
tidal thistle
fast yacht
tidal thistle
#

oh lol

fast yacht
#

wouldve clarified if i had noticed, sorry

tidal thistle
fast yacht
#

im lost on that at this point lmao

#

ill have to research that later, don't have the time rn unfortunately

tidal thistle
#

i don't really grok what the difference between a preorder and partial order is

#

maybe that you can have two types that are "the same" but are still distinguishable?

olive fable
#

It's basically that in a preorder you could have X is a subtype of Y and Y is a subtype of X, whereas in a partial order that's not possible (unless X == Y).