最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

typescript - Optional object member causes compilation error. Is there a directive to suppress the error? - Stack Overflow

programmeradmin5浏览0评论

My question: is there a directive in comment that would tell typescript compiler to ignore whatever it considers error in the line of code following the directive?

I was looking in typescript docs, I was googling but could not find the answer.

I have a typescript class containing some optional members, like this:

import providers from "./components.json"

import { Socket } from 'node:net'

/**
 * TcpLink represents control and data communication channels 
 * (in some cases only control) 
 * to send and receive data and commands to and from 
 * other programs (components) that provide someuseful function:
 * radio equipment control, software modem, protocol wrapper
 * etc. The programs may have individual locations and other than 
 * default TCP ports configured and that's why the class should be
 * configurable by means of a JSON file.
 * In this example Socket is not used, as the question only 
 * related to problems in the constructor
 **/
export class TcpLink {
    cmd?: Socket ;          // control connection socket
    data?: Socket ;         // data connection socket
    dataPort? : number ;    // data TCP port number
    controlPort?: number ;  // control TCP port number
    name: string ;          // symbolic name of the component to attach to
    /** Constructor will accept provider name and retrieve parameters,
     *  but will not connect yet
     */
    constructor( providerName : string ) {
        this.name = providerName 
        const ports = providers[providerName as keyof typeof providers]?.ports 
        if( ports === undefined ) {
            throw (new Error(`ERR001: component ${providerName} not defined in file components.json`))
        }
        else {
            this.dataPort = ports.data 
            this.controlPort = ports.control
        }
    }
  /* the rest of the implemenation is omitted */
}

The configuration JSON file looks like this:

{
    "rigctld": {
      "command": "/usr/bin/rigctld",
      "ports": {
        "control": 4532
      }
    },
    "ardop": {
      "command": "/home/ok4rm/.local/ardopcf",
      "ports": {
        "control": 8515,
        "data": 8516
      }
    },
    "vara": {
      "command": "/usr/bin/wine c:/VARA/VARA.exe",
      "ports": {
        "control": 8301,
        "data": 8300
      }
    }
}

rigctld is only a control program, it does not communicate any "data" and there is only one TCP connection to it, therefore it has no data attribute.

Now the problem is, if I write the line

this.dataPort = ports.data 

in plain javascript, there is absolutely no problem (except there are no classes, of course) and this.dataPort would be undefined which is perfectly OK and later in the lifecycle is handled properly.

However, in typescript, the compiler throws this error

Property 'data' does not exist on type '{ control: number; }'.

(referring to the JSON attribute with no data member).

It forces me to rewrite the code this way just to make it shut up:

if( 'data' in ports ) this.dataPort = ports.data

but it is just an annoying workaround for a line that would work as expected in plain javascript. (BTW there is another annoying workaround a few lines above, the assignment const ports = ..., see also Element implicitly has an 'any' type because expression of type 'string' can't be used to index)

My question: is there a directive in comment that would tell typescript compiler to ignore whatever it considers error in the line of code following the directive?

I was looking in typescript docs, I was googling but could not find the answer.

I have a typescript class containing some optional members, like this:

import providers from "./components.json"

import { Socket } from 'node:net'

/**
 * TcpLink represents control and data communication channels 
 * (in some cases only control) 
 * to send and receive data and commands to and from 
 * other programs (components) that provide someuseful function:
 * radio equipment control, software modem, protocol wrapper
 * etc. The programs may have individual locations and other than 
 * default TCP ports configured and that's why the class should be
 * configurable by means of a JSON file.
 * In this example Socket is not used, as the question only 
 * related to problems in the constructor
 **/
export class TcpLink {
    cmd?: Socket ;          // control connection socket
    data?: Socket ;         // data connection socket
    dataPort? : number ;    // data TCP port number
    controlPort?: number ;  // control TCP port number
    name: string ;          // symbolic name of the component to attach to
    /** Constructor will accept provider name and retrieve parameters,
     *  but will not connect yet
     */
    constructor( providerName : string ) {
        this.name = providerName 
        const ports = providers[providerName as keyof typeof providers]?.ports 
        if( ports === undefined ) {
            throw (new Error(`ERR001: component ${providerName} not defined in file components.json`))
        }
        else {
            this.dataPort = ports.data 
            this.controlPort = ports.control
        }
    }
  /* the rest of the implemenation is omitted */
}

The configuration JSON file looks like this:

{
    "rigctld": {
      "command": "/usr/bin/rigctld",
      "ports": {
        "control": 4532
      }
    },
    "ardop": {
      "command": "/home/ok4rm/.local/ardopcf",
      "ports": {
        "control": 8515,
        "data": 8516
      }
    },
    "vara": {
      "command": "/usr/bin/wine c:/VARA/VARA.exe",
      "ports": {
        "control": 8301,
        "data": 8300
      }
    }
}

rigctld is only a control program, it does not communicate any "data" and there is only one TCP connection to it, therefore it has no data attribute.

Now the problem is, if I write the line

this.dataPort = ports.data 

in plain javascript, there is absolutely no problem (except there are no classes, of course) and this.dataPort would be undefined which is perfectly OK and later in the lifecycle is handled properly.

However, in typescript, the compiler throws this error

Property 'data' does not exist on type '{ control: number; }'.

(referring to the JSON attribute with no data member).

It forces me to rewrite the code this way just to make it shut up:

if( 'data' in ports ) this.dataPort = ports.data

but it is just an annoying workaround for a line that would work as expected in plain javascript. (BTW there is another annoying workaround a few lines above, the assignment const ports = ..., see also Element implicitly has an 'any' type because expression of type 'string' can't be used to index)

Share Improve this question edited Mar 20 at 14:00 Jindrich Vavruska asked Mar 20 at 7:03 Jindrich VavruskaJindrich Vavruska 83210 silver badges26 bronze badges 1
  • Please edit the code here to be a minimal reproducible example we can copy and paste into our own IDEs to see what you're seeing. Right now you're doing some multi-file thing which is harder to use, and if we do use it, it looks like you've named the keys different things and are using undeclared types like Socket. These are barriers for others to start working on your issue, and make it less likely that any answer you get will have been tested first. – jcalz Commented Mar 20 at 13:12
Add a comment  | 

1 Answer 1

Reset to default 1

is there a directive in comment that would tell typescript compiler to ignore whatever it considers error in the line of code following the directive?

The direct answer to this is "yes": // @ts-ignore or // @ts-expect-error.

However, rather than suppressing such errors I would suggest addressing them. Your primary complaint seems to be that providers is too narrowly-typed, which you could change like so:

import providersFromJSON from "./components.json"

type ProviderName = keyof typeof providersFromJSON
type Provider = {
    command: string
    ports: {
        control?: number
        data?: number
    }
}

const providers: Record<ProviderName, Provider> = providersFromJSON

This will also help you catch future mistakes/typos in components.json.

Additionally, to eliminate the other annoying workaround you mentioned, type providerName more narrowly (as ProviderName rather than string):

constructor( providerName : ProviderName ) {
    this.name = providerName 
    const ports = providers[providerName]?.ports 
    if( ports === undefined ) {
        throw (new Error(`ERR001: component ${providerName} not defined in file components.json`))
    }
    else {
        this.dataPort = ports.data 
        this.controlPort = ports.control
    }
}

Putting all of that together, here's a complete/self-contained example.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论