Implicitt avvecklade optionals i Typescript?


I Swift, om jag har en egenskap i en klass som är en annan klass, deklarerar jag den som ett implicit avpackat valfritt värde:

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() 
  }
}

I Typescript tror jag att jag måste göra det på det här sättet:

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
    }
  }
}

Finns det ett sätt att göra implicit uppackade optionals i TypeScript? Är det kanske på gång?

Svar #1

Ja, Typescript har denna funktionalitet, det kallas Definite Assignment Assertion och ser ut så här (observera utropstecknet):

let x! string; // variable declaration
class Foo {
  bar!: number; // property declaration
}

Notera dock att i TypeScript har definitivt tilldelade variabler/egenskaper typen T, inte Optional<T>, som i Swift, och blir bara undefined när de inte är tilldelade, så de är bara ett sätt att kringgå typkontrollregler och påverkar inte körningstiden. Du får inte fel som got nil while implicitly unwrapping optional value, men du får bara undefined och först när du försöker använda det (till exempel försöker anropa en metod) får du ett fel, jämför: 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

Så, var försiktig, definitiv tilldelning är en stor fälla

Svar #2

I TS (gissar samma i Swift) kan du också definiera värde i konstruktorn. Därför, om du inte förväntar dig att värdet ska vara null - bör du inte lägga till det i typen.

Här är lekplatsen

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)
    }
  }
}

Relaterade artiklar