5 ms·
You can fix that fairly easily using private variables: class A { private value: number } class B { private value: number } const x: A = new
by MrJohz 2y ago
You can fix that fairly easily using private variables:
class A {
private value: number
}
class B {
private value: number
}
const x: A = new B() // error
You can also use the new Javascript private syntax (`#value`). And you can still have public values that are the same, so if you want to force a particular class to have nominal typing, you can add an unused private variable to the class, something like `private __force_nominal!: void`.
- DanielHB 2y agoThere is nothing to fix in my example, I was just highlighting the difference between nominal and structural typing. Adding a private field to the class is a form of branding (just like adding a Symbol key to a primitive).
- MrJohz 2y agoThe point is that Typescript does have nominal typing. It's used if a class is declared with any kind of private member, and for `unique symbol`s. So both in the case I showed, and the case shown in the article, we are using true nominal types. In fairness, we're also using branded types, which I think is confusing the matter here*. But they are specifically branded nominal types. We can also create structurally-typed brands (before the `unique symbol` technique, that was the only possible option). I think that's what the previous poster was referring to by "simulated nominal typing" — this is distinct from using `unique type` and private members, which are true nominal typing. * Note: Branded types aren't necessarily a well-defined thing, but for the sake of the discussion let's define them so: a branded type is a type created by adding attributes to a type that exist at compile time but not at runtime.
- davorak 2y ago> which are true nominal typing. One part that was not clear to me without testing, and since I do not use typescript regularly, was that you only get nominal typing between the classes that share the private member and if you start going out side that set you lose nominal typing. So you do not get a nominal type, but you can get a subset of types that when interacting with each other act as if they were nominal types. So class Cat that uses `private __force_nominal!: void` can still be used as class Dog if Dog does not have `private __force_nominal!: void`. Example[1]: class Dog { breed: string constructor(breed: string) { this.breed = breed } } function printDog(dog: Dog) { console.log("Dog: " + dog.breed) } class Cat { private __force_nominal!: string breed: string constructor(breed: string) { this.breed = breed } } const shasta = new Cat("Maine Coon") printDog(shasta) edit - the above type checks in typescript 5.4.5 [1] modified example from https://asana.com/inside-asana/typescript-quirks https://asana.com/inside-asana/typescript-quirks
- ackfoobar 2y agoWithout your example, I would've bet that TS uses structural typing for interfaces and nominal typing for classes.
- DanielHB 2y agoI thought so too originally, was very surprised.
- davorak 2y agoThis is pretty much to flowjs does flowtype documentaiton: https://flow.org/en/docs/lang/nominal-structural/#toc-objects-are-structurally-typed https://flow.org/en/docs/lang/nominal-structural/#toc-object... Example: https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SQA9KyAAQwIgAdxWxgAOj5VhyAPJoABWABURQBeDnADnUzwrZAc+ymKAIDn0gDcQv52DFkplxgATBz5YrlSZVeqpBVtXqhW0JByIJK1eLpasLVabZQ7QKQE1cDJgzr9VBXRyFvYvSa5e7JbqOeyOQB1CCULYkIVCp4YEgkDkAEQg2uAQo5NY5aBYpTVGsd1drtg1QmU2YAFPXsI37ZqEABKBWt2u1iS1WlWPulS11htscc6oX0-OwB7KODQJWaiTlhDdtgVtWH0dVqAT9sQNpWIhH4OHtURgDUHJPCFnS+Ha43heLDkAGFMjHK9aznNgmwdLUV3bKROzSSheyXaChwvFcJynGdIIXSCV3XKBCILaB7HVWoi0sBcvh5YDMm7YMAFkUS+YDiCgYNfygZgKgPCtuxICj7AwUd0wAUWobMAEJchDEwSB3KAkgaAAGKwzQAZgANisFSQHpIA https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAzt...