Live data from Hacker News

Making sense of TypeScript using set theory

blog.thoughtspile.tech

21–30 of 94 posts

Re: Making sense of TypeScript using set theory

#21

Earlier quoted context omitted.

The problem with using any where you don't care about the type is that someone can come along and make unchecked assumptions about what type it actually is. Unknown is spicier as it'll prevent developers from assuming it's a string or object or something.

That makes some sense to me. I’m not a TypeScript dev so I apologize for the stupid question. Is there any functional difference between the two? I.e. is there a case where using Unknown instead of Any will result in some sort of “compile” time error opposed to a runtime?

Yes. `any` really does turn off all type checking. You see that offhand mentioned in this article talking about some of the paradoxes of `any`. `unknown` is still type checked and is arguably "merciless" type-checked that to do much of anything with an `unknown` you have to check for a more specific type first or the compiler returns an error that what you are doing isn't known to be valid for `unknown`.

Some of that happens "automatically" at this point in the large number of ways that types can now be narrowed implicitly in Typescript (type guards [library functions], type asserts, the `typeof` runtime operator, the `in` runtime operator [as of recently], etc), so it can feel like `unknown`/`any` are the same up to a point, that point being where the runtime type is trivially known based on if statements and library functions around your use of the type.

(Fun fact: `any` predates most type narrowing and `unknown` by several major Typescript versions. So `any` beyond just being the final "escape hatch" from type checking is also something of a legacy tool.)

Re: Making sense of TypeScript using set theory

#22

I might be missing something, but isn't this line backwards? > Subtype of type A is a subset of type A. Supertype is a superset. Easy. Subtype of type A is actually a superset of type A, since it contains at least all the properties of A. If you had (contrived example) a Dog class that inherited from an Animal class, Dog would be a sub type of Animal, but its additional properties (say, a bark() method) mean that it…

In your case, dogs are only those animals that bark. That's a subset of animal. Think of it this way: can you think of an object that satisfies (is-a) Dog, but not Animal? No. Can you think of an object that satisfies Animal, but not Dog? Yes. So Dog ⊂ Animal.

hbrn has it right calling those properties constraints, not features. With anything but a sealed class, the properties that are not present are unspecified rather than missing.

And indeed sealed classes feel very "un-set-theoretic" to me.

Re: Making sense of TypeScript using set theory

#23

I might be missing something, but isn't this line backwards? > Subtype of type A is a subset of type A. Supertype is a superset. Easy. Subtype of type A is actually a superset of type A, since it contains at least all the properties of A. If you had (contrived example) a Dog class that inherited from an Animal class, Dog would be a sub type of Animal, but its additional properties (say, a bark() method) mean that it…

Nope. This is a common confusion.

The set of properties of objects and the sets of objects themselves have a complementary relationship when it comes to union / intersection and subset / superset.

Let's define a "property" as being a predicate that is true for all elements of a set. For example, a collection of red objects has the "red" property.

A subset of a set of objects can only have the same or more properties than the set you started with. If you take a bunch of marbles of varying colors, selecting a subset of those marbles can yield a set with a new property (such as them all being red), but they are guaranteed to have the "marble" property.

A superset of objects can only have the same or fewer properties than the set you started with. Adding marbles to an existing set of marbles can only make "they are all red" become false (if it was true to begin with).

Union and intersection have the same duality; the union of two sets has the intersection of its properties, and the intersection of two sets has the union of its properties.

These results come from logic, not TypeScript.

Re: Making sense of TypeScript using set theory

#24

I might be missing something, but isn't this line backwards? > Subtype of type A is a subset of type A. Supertype is a superset. Easy. Subtype of type A is actually a superset of type A, since it contains at least all the properties of A. If you had (contrived example) a Dog class that inherited from an Animal class, Dog would be a sub type of Animal, but its additional properties (say, a bark() method) mean that it…

> 4. A extends B ... can be read as "A is subset of B".

I agree, it is unnatural to think of a subset as "extending" the set it is part of.

Re: Making sense of TypeScript using set theory

#25

Earlier quoted context omitted.

That makes some sense to me. I’m not a TypeScript dev so I apologize for the stupid question. Is there any functional difference between the two? I.e. is there a case where using Unknown instead of Any will result in some sort of “compile” time error opposed to a runtime?

Yes - trying to access a property or method on something typed as unknown will (almost?) always result in a compile time error because it's unknown whether the value has that property or not. https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABAd...

always, because "unknown" includes null / undefined, which don't allow property access at all.

Re: Making sense of TypeScript using set theory

#26
post #18

Earlier quoted context omitted.

Fair enough, "is assignable to" is another synonym for "is subset of". I find it much easier to reason about things I can visualize, like sets, which is why I love my set interpretation. Edit: besides, it's quite unintuitve that "never" is assignable to anything. How can never be something?

Because "never" is an empty set and empty set is a subset of all sets.

Exactly, that's why I wrote the article =) Makes perfect sense in "set world", but not in "common sense" based on your feeling of the word "never"

Re: Making sense of TypeScript using set theory

#27

Earlier quoted context omitted.

I think "unknown" is more than that! Basically it's a way to say you don't care about the type, as in Record or P extends Promise

But you have to care about the type with unknown? For instance calling this on an unknown obj.value Will return a type error that value doesn’t exist on unknown. While calling it on an ant is valid typing

> But you have to care about the type with unknown?

It's better to say `unknown` is a promise that you won't care about the type. When you write `obj.value`, you're caring about the type. TypeScript sees that and says "hey, you promised you wouldn't care about this type."

> While calling it on an ant is valid typing

It's still invalid, same as if you'd used `unknown`. It just suppresses the type error. The presence of `any` in a codebase is a very real risk. The only reason it exists is to allow incremental porting from JavaScript to TypeScript.

Re: Making sense of TypeScript using set theory

#28

The difference between `any` and `unknown` is that `any` is an escape hatch from the type system. `any` can be used anywhere and will satisfy any type constraint. `any` is how the developer says to the type system "trust me, I know what I'm doing, don't worry about this particular value." Unknown, on the other hand, is for untyped code from an imported JS library, JSON data received from the network that may or may n…

> I know what I'm doing

`any` can also be an indicator of the exact opposite.

Re: Making sense of TypeScript using set theory

#29

I might be missing something, but isn't this line backwards? > Subtype of type A is a subset of type A. Supertype is a superset. Easy. Subtype of type A is actually a superset of type A, since it contains at least all the properties of A. If you had (contrived example) a Dog class that inherited from an Animal class, Dog would be a sub type of Animal, but its additional properties (say, a bark() method) mean that it…

Nope. This is a common confusion. The set of properties of objects and the sets of objects themselves have a complementary relationship when it comes to union / intersection and subset / superset. Let's define a "property" as being a predicate that is true for all elements of a set. For example, a collection of red objects has the "red" property. A subset of a set of objects can only have the same or more properties…

maybe a dumb question, but why does wikipedia say typescript is a superset of javascript?

https://en.wikipedia.org/wiki/TypeScript

Re: Making sense of TypeScript using set theory

#30
Having set types like this and refining them smaller is something I wish Haskell would learn from Typescript, especially the automatic inference side. I wonder if it would help with linear types? Are there any proposals? I know there are type level naturals in the type system, but this is more like wanting to deconstruct existing types like Int or String into subset types.

e.g.,

foo :: Int -> 3::Int | 4::Int

foo 4 = 4

foo _ = 3

bar :: 3::Int | 4::Int -> Bool

bar 4 = True

bar 3 = False

-- (bar 12) is a compiler error, and no need to handle other patterns

baz :: 3::Int | 2::Int -> Bool

bar 3 = True

bar x = False -- Type of x is 2::Int

Post reply on HN