Jonathan Tuzman
Jonathan Tuzman

Reputation: 13289

Implicitly Unwrapped Optionals in Typescript?

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

Answers (2)

fantom
fantom

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

ValeriiVasin
ValeriiVasin

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

Related Questions