Reputation: 13289
In Swift, if I have a property of a class that is another class, I declare it as an implicitly unwrapped optional:
class MyClass {
var prop: OtherClass!
init(prop: OtherClass) {
self.prop = prop
}
explodeProp() {
// don't need to unwrap it, because it's implicitly unwrapped
// which is safe because it's always assigned in the initializer
prop.explode()
}
}
In Typescript, I think I have to do it this way:
export class MarkdownNode {
tag = "";
text = "";
document: FoldingDocument | null = null; // will never actually be null
parent: MarkdownNode | null = null; // could indeed be null
constructor(tag: string, text: string, document: FoldingDocument) {
this.tag = tag;
this.text = text;
this.document = document;
}
addSibling(node: MarkdownNode) {
if (!this.parent) {
this.document!.nodes.push(node) // no choice but to force-unwrap?
} else {
this.parent.children.push(node
}
}
}
Is there a way to do implicitly unwrapped optionals in TypeScript? Is it maybe on the way?
Upvotes: 5
Views: 11845
Reputation: 565
Yes, Typescript has this functionality, it is called Definite Assignment Assertion and looks like this (note exclamation mark):
let x! string; // variable declaration
class Foo {
bar!: number; // property declaration
}
Note, however, that in typescript definitely assigned variables/properties has type T
, not Optional<T>
, as in Swift, and just become undefined
when unassigned, so they are just the way to violate typecheck rules and doesn't affect runtime behaviour. You will not get errors like got nil while implicitly unwrapping optional value
, but you just will get undefined
and only when you try to use it (like trying to call method), you get error, compare:
Swift
class Foo {
var bar: String!
}
let x = Foo()
let y: String = x.bar // boom! Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
Typescript:
class Foo {
bar!: string;
}
let x = new Foo()
let y: string = x.bar // it is ok, we just assigned `undefined` to string variable
someObject.name = y;
// years later in a galaxy far far away
let nameLength = someObject.name.length; // boom! Uncaught TypeError: Cannot read property 'length' of undefined
So, be careful, definite assignement is big footgun
Upvotes: 7
Reputation: 8716
In TS (guess same in swift) you could define value in constructor as well. Therefore if you dont expect value to be null
- you should not add it to the type.
Here is playground
class FoldingDocument {
nodes: MarkdownNode[] = [];
}
class MarkdownNode {
tag: string;
text: string;
document: FoldingDocument;
parent: MarkdownNode | null = null; // could indeed be null
children: MarkdownNode[] = [];
constructor(tag: string, text: string, document: FoldingDocument) {
this.tag = tag;
this.text = text;
this.document = document;
}
addSibling(node: MarkdownNode) {
if (!this.parent) {
this.document.nodes.push(node) // no choice but to force-unwrap?
} else {
this.parent.children.push(node)
}
}
}
Upvotes: 0