5 ms·
I have never encountered issues with JS libraries lying in their type definitions (like not including `T|undefined` in the type if `undefined` is a possible ret
by realharo 6y ago
I have never encountered issues with JS libraries lying in their type definitions (like not including `T|undefined` in the type if `undefined` is a possible return value).
More often this can happen with external data (typing incoming JSON responses), but you have to run-time validate those anyway.
`null` is only rarely used in JS, `undefined` is by far the more common one, and of course the types reflect which one is a possible value, so it's not like you can miss it by accident.
Falsy values are only a problem with bad practices - inside `if`, I just always use the full form with the `===` operator, e.g. `if (variable !== undefined)` instead of `if (variable)`. A lint rule can be enabled for that. There is now also the `??` operator which prevents the common misuse of `||`, e.g. `const a = variable ?? 'default'`.
So those things aren't really issues in practice.
You are correct in assuming that I'm not very familiar with Dart, I have only used it very briefly. I have only checked whether specific features such as sum types were available.
- mythz 6y ago> `null` is only rarely used in JS, `undefined` is by far the more common one, and of course the types reflect which one is a possible value, so it's not like you can miss it by accident. That's not true, `undefined` is not even a keyword or type, `null` is what you would use if you wanted to specify a variable has "no value" in JS or JSON (again because `undefined` isn't a Type). The "undefined" value is only for specifying if the variable "does not exist". The difference is important as the behavior is different depending on how you use them. > I just always use the full form with the `===` operator, e.g. `if (variable !== undefined)` instead of `if (variable)` This is bad practice as you're only testing for `undefined` here, not `null`, this is basically the only time where strict equality isn't useful. You want to test with `if (variable != null)` which tests for both `null` and `undefined` and not other falsy values that `if (variable)` tests for. > There is now also the `??` operator Right, the Nullish coalescing operator (which Dart/C# also has) tests for both `null` and `undefined` (well `void 0` since the `undefined` value can be overridden) and not falsy values.
- realharo 6y agoRegarding the `if`, it only makes sense to test for things that the type actually contains. So if I have a type `User|undefined`, testing `if (user === undefined || user === null)` is pointless, as `null` is not part of that type. It would be different if it were. Similarly, it makes no sense to test a variable of `User` type for value `false`, like it would if the type were `User|boolean`, or even `User|false` which you can do in TypeScript (not that you should). So `if (variable)` is still bad (ok for booleans, tolerable for some types but better avoided). You only test for what the variable can contain. Some types you encounter are `T|null` - mostly DOM things (e.g. the return value of getElementById), but some JSON stuff as well like you said. Even though a lot of JSON just has optional properties instead, which for all intents and purposes work like `|undefined` when reading them. From my experience, it is much more common to deal with `undefined` in the JS ecosystem, whether that is by omitting properties from objects, or explicitly assigning/returning `undefined` somewhere. `T|null|undefined` types are ever rarer. Only for those it makes sense to test for both null and undefined. By the way you can also have types like type RemoteData<T> = {ready: false} | {ready: true, data: T} in TypeScript, which is better than { ready: boolean, data?: T } because you don't have to worry about "does `data` still make sense when it is non-ready?", the type clearly tells you that it doesn't (of course you can also have a different type where it would, the point is to accurately describe the structures you deal with). Then, if you do a check if (remote.ready) { console.log(remote.data.length) } it knows that data exists inside that `if` block, so you can safely access it without `!` or `?`. Similarly, inside `if (!remote.ready) { }`, you cannot access it at all. It also won't let you pass an object with { ready: true }, but no data of the required type to `RemoteData<T>`.
- mythz 6y ago> So if I have a type `User|undefined`, testing `if (user === undefined || user === null)` is pointless, as `null` is not part of that type. It's very relevant, your TypeScript definition is meaningless at runtime when it's executed JS where all TypeScript's type information is erased, the only checks are relevant are the runtime JS type checks. > `if (user === undefined || user === null)` is pointless Right, it is verbose & unecessary, so is only testing for `if (user === undefined)` which is inadequate and I don't know anyone who'd use it since using the recommended `if (user == null)` is shorter and more complete for testing if any value is not `null` or `undefined`. If you're validating JSON you should know that there is no `undefined` type in JSON, but any value could be `null`. > From my experience, it is much more common to deal with `undefined` in the JS ecosystem, whether that is by omitting properties from objects, or explicitly assigning/returning `undefined` somewhere. If a type want's to declare that property exists but doesn't have a value it would be `null`, which is also the only option you have in JSON to do so. Your TypeScript definitions are for your code structure and API description so you can benefit from its static analysis, but you should be aware they do nothing at runtime where all Type annotations are erased so if you try to define your Vue component with an optional property, e.g: class MyComponent extends Vue { p1?:string; p2 = null; } It gets stripped away completely but setting a null value instead will ensure the property exists and is made reactive: var MyComponent = /** @class */ (function (_super) { __extends(MyComponent, _super); function MyComponent() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.p2 = null; return _this; } return MyComponent; } It's important to know what guarantees TypeScript does for you, what effects the type annotations have and what their behavior is at runtime.