Order of execution missing in class

On numerous occasions, I find myself facing the same dilemma. The data types are incorrect and additional verification is required.

Let's consider a simple example, where we have a Car class that allows us to retrieve a model name. Upon initialization of this class, the model property is set to null.

We have two methods: one to set and another to get the model:

class Car {
    private model: string | null

    setModel() {
        this.model = 'a3'
    }
  
    getModel() {
        return this.model
    }
}

While using this class, everything seems to work as expected, with the model being correctly defined in the order of execution.

But TypeScript only recognizes the original type as a string or null.

function searchForBrand(model: string) {
    if (model === 'a3') return 'audi'

    return ''
}


const car = new Car()
car.setModel()

console.log(car) // { model: 'a3' }

const currentModel = car.getModel()
console.log(currentModel) // a3

searchForBrand(currentModel) // Error: Argument of type 'string | null'

I am inclined to use ! (even though it's not ideal), or handle this issue within my function or beforehand. This solution involves extra steps and might not be the most effective approach. What do you think?

Playground

The actual scenario where I face a similar challenge:

class Stream {
  idealConstraint = {
    width: { ideal: 1920 },
    height: { ideal: 1080 },
    frameRate: { ideal: 60 },
    advanced: [ { zoom: 2 } ]
  }
  flux: MediaStream | null = null

  async useStreamWithConstraints() {
    const constraints = {
      video: {
        facingMode: FACING_MODE.ENVIRONMENT,
        noiseSuppression: true,
      },
      audio: false
    }
  
    await this.useUserStream(constraints)
    if (APP_MODE === 'development') await this.useDevelopmentStream() 

    await this.applyVideoConstraints(this.idealConstraint)
    
    return this.flux
  }

  async useUserStream(constraints: MediaStreamConstraints) {
    this.flux = await navigator.mediaDevices.getUserMedia(constraints)
  }

  async useDevelopmentStream() {
    const developmentDeviceId = (await navigator.mediaDevices.enumerateDevices()).filter(device => device.label === 'OBS Virtual Camera')[0]?.deviceId
    const developmentStream = await navigator.mediaDevices.getUserMedia({ video: { deviceId: developmentDeviceId } })
    const developmentStreamDeviceId = developmentStream.getVideoTracks()[0]?.getCapabilities()?.deviceId

    if (developmentStreamDeviceId === developmentDeviceId) this.flux = developmentStream
  }

  async applyVideoConstraints(constraints: MediaTrackConstraints) {
    try {
      const videoTrack = this.flux?.getVideoTracks()[0]
      await videoTrack?.applyConstraints(constraints)
    } catch (error) {
      console.error('Could not apply constraints')
    }
  }

  getFluxSettings() {
    return this.flux?.getVideoTracks()[0]?.getSettings()
  }

  getFluxCapabilities() {
    return this.flux?.getVideoTracks()[0]?.getCapabilities()
  }

  setZoom(zoomValue: number) {
    return this.applyVideoConstraints({
      advanced: [{ zoom: zoomValue }]
    })
  }
}

Answer №1

In the previous comment by @jonrsharpe, it was suggested that a better approach might be to prevent the creation of any invalid instances of Car. Instead, consider passing the model as a parameter in the constructor to set it during the initialization of the Car object.

class Car {
    constructor(private model: string){}
  
    getModel(): string {
        return this.model
    }
}

function searchForBrand(model: string) {
    if (model === 'a3') return 'audi'

    return ''
}


const car = new Car('a3')

const currentModel = car.getModel()
searchForBrand(currentModel)

Playground

Answer №2

Here is the updated code that may be helpful to someone. If there are any missing parts, feel free to leave a comment.

Thank you for the insightful explanation.

class Stream {
  static idealConstraint = {
    width: { ideal: 1920 },
    height: { ideal: 1080 },
    frameRate: { ideal: 60 },
    advanced: [ { zoom: 2 } ]
  }
  flux: MediaStream

  constructor(flux: MediaStream) {
    this.flux = flux
  }

  static async create() {
    const flux = await this.#getUserFlux()
    const developmentFlux = await this.#getDevelopmentFlux()
    const usedFlux = developmentFlux ?? flux

    await this.#applyFluxConstraints(usedFlux, this.idealConstraint)

    return new this(usedFlux)
  }

  static #getUserFlux() {
    const constraints = {
      video: {
        facingMode: FACING_MODE.ENVIRONMENT,
        noiseSuppression: true,
      },
      audio: false
    }

    return navigator.mediaDevices.getUserMedia(constraints)
  }

  static async #getDevelopmentFlux() {
    if (APP_MODE !== 'development') return

    const developmentDeviceId = (await navigator.mediaDevices.enumerateDevices()).filter(device => device.label === 'OBS Virtual Camera')[0]?.deviceId
    if (!developmentDeviceId) return

    const developmentStream = await navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: developmentDeviceId } } })

    return developmentStream
  }

  static async #applyFluxConstraints(flux: MediaStream, constraint: MediaTrackConstraints) {
    try {
      const videoTrack = flux.getVideoTracks()[0]
      await videoTrack.applyConstraints(constraint)
    } catch (error) {
      console.error('Could not apply constraints')
    }
  }

  get currentZoom() {
    return this.flux.getVideoTracks()[0].getSettings().zoom
  }

  getFluxCapabilities() {
    return this.flux.getVideoTracks()[0].getCapabilities()
  }

  setZoom(zoomValue: number) {
    const zoomConstraint = {
      advanced: [{ zoom: zoomValue }]
    }

    return Stream.#applyFluxConstraints(this.flux, zoomConstraint)
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for choosing and filtering the preferred object in ES6

Consider this array structure: const testData = [ { group: "Team1", info: [ { key: 123, person: "Alice", type: "Football" }, { key: 456, person: "Bob", type: " ...

Creating a String Array and linking it to an Input Field

I'm currently working on a code that involves mapping through an array of strings using observables. My objective is to display the value from this array inside an input field. However, despite being able to view the array in the console, I encountere ...

Numerous mistakes detected in the TypeScript code

I've implemented the following class within an ASP.NET Core React application: import * as React from 'react'; interface MyInputProps { inputType: string; id: string; className: string; parentFunctio ...

Enhance your workflow with Visual Studio Code by incorporating multiple commands

Embarking on my journey to create my first VSC extension by following this tutorial. Within the "extension.ts" file resides a simple hello world command. My ambition is to introduce another command called git_open_modified_files, however, the tutorial la ...

Guide to setting up a trigger/alert to activate every 5 minutes using Angular

limitExceed(params: any) { params.forEach((data: any) => { if (data.humidity === 100) { this.createNotification('warning', data.sensor, false); } else if (data.humidity >= 67 && data.humidity <= 99.99) { ...

Angular 6 - Using properties in classes

Considering a component structured as follows: import { Component, OnInit, ViewChild } from '@angular/core'; @Component({ selector: '...', templateUrl: './...html', styleUrls: ['./...scss'] }) export class Te ...

A static method written in Typescript within an abstract class for generating a new instance of the class itself

Imagine I have abstract class Foo { } class Bar1 extends Foo { constructor(someVar) { ... } } class Bar2 extends Foo { constructor(someVar) { ... } } I want to create a static method that generates an instance of the final class (all construct ...

The TypeScript error "Uncaught ReferenceError: require is not defined" occurs when the

When attempting to export a namespace from one .ts file and import it into another .ts file, I encountered an error: NewMain.ts:2 Uncaught ReferenceError: require is not defined. As someone new to TypeScript, I am still in the learning process. Below is a ...

How can I ensure a function only runs after all imports have been successfully loaded in Vue 3?

Encountering an issue with importing a large quantitative variable in Vue 3. Upon running onMounted, it seems that the import process is not yet complete, resulting in an error indicating that the variable tesvar is "uninitialized". The code snippet prov ...

Modify the scope in the middle of a scope function

UPDATE: I've created a JSFiddle: http://jsfiddle.net/U3pVM/18137/ I'm looking to make the black section move up FIRST, followed by the green sliding across. I'm struggling to achieve this effect. Keep reading for more details: Note: The co ...

Is it beneficial to use TypeScript for writing unit tests?

We are in the process of transitioning from JavaScript to TypeScript within my team. One question that has come up is whether we should also migrate our unit tests from JavaScript to TypeScript. Personally, I am not convinced of the significant benefits o ...

Using variables within the useEffect hook in ReactJS

I am currently working on a project using Reactjs with Nextjs. I am facing an issue where I need to retrieve the value of "Editor" and alert it inside the handleSubmit function. Can anyone help me with how to achieve this? Here is my code snippet, any as ...

Creating a unique type with a suffix of `px`

Understanding how to create a Position type class is clear: class Position { x: number = 0; y: number = 0; } However, I now require the x and y values to be integers with the suffix of px, like this: const position = { x: '1px', y: &ap ...

When dealing with ng effects, an undefined value replaces the stream observable

Currently, I am working on a flow that involves adding a new object to another object's collection. This process starts with some domain-related tasks. Initially, I send an object to the backend and upon receiving a callback, I trigger another action ...

In React Typescript, the input type="checkbox" does not show any value in the value attribute

I'm facing an issue with displaying text next to a checkbox in React Typescript. When I try to use the value attribute, it doesn't seem to work as expected. Also, attempting to set innerHTML throws an error stating that input is a void element ta ...

Error: module not found in yarn

https://i.sstatic.net/3zEMq.png In my yarn workspace, I have organized folders named public and server. While working with TypeScript in VS Code, I encounter an error message stating: Cannot find module 'x' Interestingly, even though the error ...

Issue with accessing global variable in nested function using "this" in Angular 2

Having recently delved into Angular 2, I find myself facing a challenge with accessing the "task_title" within the startTimer() function. The console.log() returns undefined and I suspect it's due to "this" referring to the function itself instead of ...

Conflicts arise when trying to create several objects with different material types in ThreeJS within the

Adding a star to the scene caused all objects in the scene to turn white and the perspective of the objects to glitch. Switching the materialStar to new THREE.MeshBasicMaterial fixed the rendering issue. It appears that the problem stems from having multip ...

The Bootstrap modal I implemented is opening correctly, but for some reason, the form inside is not appearing

I created the AddJokeModalComponent to streamline the process of opening a form without duplicating code in every component. Below is the modal structure: <ng-template #addJokeModal> <div class="modal-content my-custom-modal"> ...

Error in React Typescript Props in ListItem (Material UI Component)

I am encountering a problem with the ContainerComponent and ContainerProps. I believe that the issue lies in the fact that "li" is defined as a type string, but it needs to be explicitly declared as type React.ElementType<React.HTMLAttributes>. Howev ...