101

I'm pretty new to TypeScript and I would like to know if there exists a good way to rewrite code to avoid TSLint error "object access via string literals is disallowed" in the following code

interface ECType
{
    name: string;
    type: string;
    elementType?: string;
}

export var fields: { [structName: string]: Array<ECType>; } = { };

class ECStruct1 {
    foo: string;
    bar: number;
    baz: boolean;
    qux: number;
    quux: number;
    corge: ECStruct2[];
    grault: ECStruct2;

    constructor() {
        ...
    }
} 

fields['ECStruct1'] = [
    { name: 'foo', type: 'string' },
    { name: 'bar', type: 'int' },
    { name: 'baz', type: 'bool' },
    { name: 'qux', type: 'long' },
    { name: 'quux', type: 'ulong' },
    { name: 'corge', type: 'array', elementType: 'ECStruct2' },
    { name: 'grault', type: 'ECStruct2' }
];

Update: At the end the content above will be part of a self-generated file with more than 300 ECStructs, so I would like to have the class definition (e.g. ECStruct1) followed by its meta-description (e.g. fields['ECStruct1']).

MartyIX
  • 27,828
  • 29
  • 136
  • 207
Denis Cappellin
  • 1,230
  • 2
  • 12
  • 22
  • 7
    I've never used TS but looking at the error and looking at the code, I'd say you need to replace `fields['ECStruct1']` with `fields.ECStruct1`. Using dot notation to access object props is usually preferred over string literal access. – Jamie Dixon Oct 28 '15 at 09:22
  • 1
    Thanks. I've already tried it, but `fields.ECStruct1=` is not allowed by the TS compiler: Error TS2339 Property 'ECStruct1' does not exist on type '{ [structName: string]: ECType[]; }'. – Denis Cappellin Oct 28 '15 at 09:28

7 Answers7

178

You have a couple options here:

1) Just disable the rule

/* tslint:disable:no-string-literal */
whatever.codeHere()
/* tslint:enable:no-string-literal */

2) Use a variable instead of a string literal

// instead of 
fields['ECStruct1'] = ...
// do something like
let key = 'ECStruct1';
fields[key] = ...

3) Write/Generate an explicit interface

See MartylX's answer above. Essentially:

interface ECFieldList {
    ECStruct1: ECType[];
}

export var fields:ECFieldList = {
    ECStruct1: [
        ...

Any of these are reasonable solutions, although I'm not as much of a fan of #2 because it's mangling up your code for no good reason. If you're generating code anyways, perhaps generating a type for fields as in #3 is a good solution.

Ricardo
  • 3,696
  • 5
  • 36
  • 50
JKillian
  • 18,061
  • 8
  • 41
  • 74
58

You can get rid of the rule. Look for tslint.json, the add a property "no-string-literal" with false, in rules::

{
"rules": {
    "no-string-literal": false,
    ... other rules ...
suhailvs
  • 20,182
  • 14
  • 100
  • 98
56

Just use template literal annotation.

fields[`ECStruct1`]
nyc_coder
  • 633
  • 7
  • 9
  • 6
    Ugly trick as it defeats the purpose of the very warning. but it solves _my_ problem in a simple way. – LosManos May 06 '20 at 14:46
  • depending on your config, this may create a new warning: ` should be ' (quotemark) tslint(1) – rouble Dec 07 '20 at 20:32
7

What about this way? I don't know if you need the indexer ([structName: string]: Array<ECType>;) or not.

interface ECType {
    name: string;
    type: string;
    elementType?: string;
}

interface ECFieldList {
    ECStruct1: ECType[];
}

export var fields:ECFieldList = {
    ECStruct1: [
        {name: 'foo', type: 'string'},
        {name: 'bar', type: 'int'},
        {name: 'baz', type: 'bool'},
        {name: 'qux', type: 'long'},
        {name: 'quux', type: 'ulong'},
        {name: 'corge', type: 'array', elementType: 'ECStruct2'},
        {name: 'grault', type: 'ECStruct2'}
    ]
};
MartyIX
  • 27,828
  • 29
  • 136
  • 207
  • I edited my questions and added more details, so this comment should be clear. I would like to avoid having the `interface` with _N_ definitions of `ECStruct` and then the `export var fields...` where I write the actual definition of every `ECStruct`. – Denis Cappellin Oct 28 '15 at 11:57
  • What is your settings for tslint? I guess you have enabled `no-string-literal` (disallows object access via string literals. - https://www.npmjs.com/package/tslint) – MartyIX Oct 28 '15 at 12:02
  • 1
    Yes, now I have the option `no-string-literal` globally enabled and only in the file with the above code I disabled it with comment `/* tslint:disable: no-string-literal */`. – Denis Cappellin Oct 28 '15 at 13:12
  • Well, use the bracket syntax with variables (i.e `fields[variable]`) and dot syntax with strings (i.e. `fields.ECStruct1`) and you should be ok. – MartyIX Oct 28 '15 at 14:15
6

Probably not the best option, but using

fields['ECStruct1'.toString()]

works too

Pergola
  • 118
  • 1
  • 5
  • 4
    Please do not do this. The linter is there because the person who set up the project wants you to follow best code practices, not hack around the linter rules. – Andy Jan 09 '20 at 15:01
1

A simple way is to define a variable to hold the value of ECStruct1:

const sampleName = 'ECStruct1';

and then, get access to the object by using the variable as index:

fields[sampleName] ...
Ali Tourani
  • 1,170
  • 3
  • 21
  • 31
0

I have faced the same error. but i tried to make use of the type of Headers of Request object and it worked for me. Below is how I managed to resolve the issue.

const objToAdd: { [key: string]: string } = {};
objToAdd.type = 'typeToAdd';
objToAdd.key = 'keyToAdd';
objToAdd.value = 'valueToAdd';

if you see the type { [key: string]: string } tells the TSLint that this object takes keys and values of type string. Similarly, { [key: string]: any } types specifies that the keys are of string type and values of are of any type

Abhilash
  • 457
  • 5
  • 9