Live data from Hacker News

TypeScript and Set Theory

ivov.dev

21–29 of 29 posts

Re: TypeScript and Set Theory

#21
post #18

Conditional type expression are indeed very powerful and, little known fact, can be used to generate types recursively. Here's a type signature from hell with its usage: type Component = { type: 'a' } | { type: 'b' }; type FoundComponents = T extends [a: infer A] ? [Extract ] : T extends [a: infer A, ...b: infer B ] ? [Extract , ...FoundComponents ] : never; export function findComponentSets (components: Component[],…

ohh that's really interesting. Any chance of open sourcing this as a library?

Re: TypeScript and Set Theory

#22

The section on how union & intersection types behave with interfaces (rather than primitives) has them flipped: a union of interfaces will allow access to only the intersection of the fields/methods of all the types (unless you do the work to distinguish between which type you're working with), while an intersection will allow access to the union of the fields/methods of the composed types. i.e. `ICat | IDog` will on…

That's incredibly interesting, because I've been using union types a while and didn't know this. I think a lot of people will get introduced to them via function signatures, and var: ICat | IDog not meaning "var could be an ICat or an IDog" is a bit unintuitive given the boolean math. But ultimately more useful? As in, code should never test whether this thing is an ICat or IDog, and I guess it's interesting that I d…

"+" is probably a bad choice: sum types are a separate thing. In TypeScript, they can be implemented as

     Sum = { tag: "left", data: X } | { tag: "right", data: Y }
Generally higher order types are named according to what they do to types, not terms. `x: ICat & IDog` means "x is in the intersection of ICat and IDog", not "x is the intersection of an ICat and an IDog". (The latter interpretation only even makes sense for record types and a few other special cases: what's the intersection of an integer and a string supposed to be?)

Re: TypeScript and Set Theory

#24

The section on how union & intersection types behave with interfaces (rather than primitives) has them flipped: a union of interfaces will allow access to only the intersection of the fields/methods of all the types (unless you do the work to distinguish between which type you're working with), while an intersection will allow access to the union of the fields/methods of the composed types. i.e. `ICat | IDog` will on…

For anyone with trouble remembering/conceptualizing this - it follows the opposite convention as bitwise operators in javascript, so it is counter-intuitive.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Re: TypeScript and Set Theory

#25
Sets isn’t just “a branch of mathematics”. Sets is the foundation of traditional mathematics. However it has problems (paradoxes). Type theory was invented to solve those problem. And most modern proof assistants are based on some variation of type theory. Type theory is in many ways much simpler than Sets: The Set axioms are built on logic. While the (Martin Loff) type theory axioms aren’t. In other words, Type theory is much simpler than Set theory. The two theories look similar at the surface level. However they are fundamentally different. Values in type theory always comes with a type. That is not the case in Set theory. It makes a huge difference to how you use the two to prove things.

Re: TypeScript and Set Theory

#26
post #18

Conditional type expression are indeed very powerful and, little known fact, can be used to generate types recursively. Here's a type signature from hell with its usage: type Component = { type: 'a' } | { type: 'b' }; type FoundComponents = T extends [a: infer A] ? [Extract ] : T extends [a: infer A, ...b: infer B ] ? [Extract , ...FoundComponents ] : never; export function findComponentSets (components: Component[],…

This is an example of Typescript kinda sorta have some of what Dependent Types will give you. The problem is that the Typescript team hasn’t fully embraced this. So instead of implementing Dependent Types (see Agda/Idris/LEAN), the team is kinda sorta implementing parts of it piece wise, inventing different syntax for each feature as they add it. A bit like templates in C++ ended up kinda sorta implementing a Turing complete functional programming language with the worlds worst syntax. It looks as if Typescript is going down the same road. It’s a bit of a mess compared with Dependently Typed languages (Agda/Idris/…)

Re: TypeScript and Set Theory

#28

The naming of TypeScript Union and Intersection types, with respects to type theory, used to be terribly confusing/contradictory: https://www.typescriptlang.org/docs/handbook/unions-and-inte... See last paragram under «Unions with common fields» Leading to terribly confusing TypeScript cheat sheets such as this (see the union and intersection venn-diagrams): https://carltheperson.com/images/magic-typescript/magic-typ…

I agree. I wish the Typescript team had simply embraced Dependent Types from the beginning instead of adding a laundry list of ad-hoc solutions with special syntax. It’s already way more complicated than it needs to be. Solving a problem you can either use a simple but powerful solution or add patch after patch forever until you kinda sorta have covered everything that the simple powerful solution would have given you. It looks as if Typescript unfortunately is going down the patches route requiring cheat sheets and memorisation to work with. Exactly what happened with C++ templates.

Re: TypeScript and Set Theory

#29
post #6

> Finally, be aware that for a conditional type to trigger distributivity, the checked generic must be by itself to the left of extends, that is, not passed into another generic or otherwise altered during the check. Ah, this helped my brain click with a problem I’ve encountered several times. I think the most common reason I encounter this is when using generic memoized components in React. The generic parameters se…

As an aside, a workaround for that case is: const Comp = React.memo(NonMemoComp) as typeof NonMemoComp

Yeah, this has been the approach I’ve used but the purist in me really goes crazy not having it “just work”. Admittedly it’s pretty hard to have casting in cases like this come back to bite you. I suppose you could even write a lint to ensure memoized component casting is correct.
Post reply on HN