6 ms·
Why write code like that, instead of extending the class with a mandatory property? The above code is going to be inscrutable to a lot of engineers, and this i
by CuriouslyC 5y ago
Why write code like that, instead of extending the class with a mandatory property? The above code is going to be inscrutable to a lot of engineers, and this isn't something like an ORM where there's a good reason for that.
- goto11 5y agoUtility types are useful for example in the React API. You have a "state" defined as a set of properties. Then you have a setState() method where you return the set of properties you want to update, which may be a subset of the full state. So if the type of the component state is TState, then the return type of setState() can be defined as Partial<TState>.
- phailhaus 5y agoA better example is `Partial`, which makes all properties on an interface optional. Lots of use cases for that, like creating a `Dictionary` type that forces you to check for undefined values, or allowing you to support partial-updates to types without having to repeat your interfaces. The other thing is that types are more often used than read. You don't need to read the `MandatoryFields` type definition often, because your IDE/typechecker will automatically enforce the contract and tell you when you're missing properties.
- srcreigh 5y agoTIL, interfaces can extend classes in TypeScript. [0] If interfaces could not extend classes, that would be a reason to use type programming. Another reason could be a generic interface. If you have a lifecycle where a type is mutable at one point but immutable at later points, you could use mapped types to enforce those constraints on the class methods generically. [0]: https://www.typescriptlang.org/play?#code/MYGwhgzhAEAKCmAnCB7AdtA3gKGn6aYAtvAFzQQAuiAlmgOYDcu+w6ViArsJSogBSES5DnXoBKLC3z5KACxoQAdEPjQAvAWLxmMgL7YD2OpSQAzMMDWwwieGkrR4AD1NoAJjATJ0UmcAUQdzs0cm9UNABtAF1mIzY0KgowEBAATzDbe0dNHH9A4PtySMxVcgByACkUeHK9aMMgA https://www.typescriptlang.org/play?#code/MYGwhgzhAEAKCmAnCB...
- nkingsy 5y agoI'm building a strongly typed form abstraction layer for work. I use code like this to express "if this generic can be undefined, this field is required. Otherwise it cannot be used". So: FormElement<string|undefined> needs to have a "disabled" function, indicating conditions under which it becomes disabled (and absent from the model), while FormElement<string> must not have a disabled function, as it will always be present in the model. One pitfall of this approach is it requires a lot of trial and error to find the incantation that both works and doesn't swallow error messages.
- kilburn 5y agoThe advantage here is that you are not repeating the type of the property twice (once as optional in the base type, once as mandatory in the extended class). Even though the code may seem inscrutable, note that the resulting type is fairly easy to understand in your IDE. That is, if you hover over the "B" to see what the type definition is, you see: type B = A & { foo: number; baz: number; } If you defined the type like this (which is equivalent to extending the class as you were proposing) and later on someone changes the type of one such mandatory properties in the base and/or extended class without changing the other, the error becomes much much weird, on the lines of: > Type 'number' is not assignable to type 'never'.(2322) Here typescript is saying that a prop cannot have a value (type never) because the base class defines it as "number?" but the extended one defines it as "string", and the intersection between them is empty. This is hard to understand when it pops out where you don't expect it. Harder than ignoring the weird "Ensure" thing, seeing what it does (the resulting type B definition) and moving on. Defining advanced types may be cumbersome, but dealing with code that uses them is still approachable. This allows the more experienced team members to "shape the ground" and less experienced members still reap the benefits even if they don't fully understand how the thing works.
- Androider 5y agoThe beginner programmer copies the property definition. The advanced programmer simply writes "type Ensure<T, K extends keyof T> = T & { [U in keyof Pick<T, K>]-?: T[U] };", thus removing the need to copy the property. The master programmer copies the property definition.
- kilburn 5y agoDo you have some argument? Without arguments, your comment has as much substance as me replying: The beginner programmer copy/pastes the code. The advanced programmer writes a function, thus removing the need to maintain copies of the code. The master programmer copy/pastes the code. It is not like "Ensure" would be a single-use thing. "Ensure" here is a utility type definition, which is what a "function in the world of types" would be.